This is what I do:
#Repository
#Transactional(propagation = Propagation.SUPPORTS)
public class ProfileDAOHibernateImpl implements ProfileDAO {
#Autowired
private SessionFactory sessionFactory;
private Session currentSession() {
return sessionFactory.getCurrentSession();
}
#Override
public Profile getProfile(String name) {
return (Profile) currentSession().createCriteria(Profile.class)
.add(Restrictions.eq("name", name)).uniqueResult();
}
...
}
Profile entity:
#Entity
#Table(name = "profiles")
public class Profile {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int Id;
#Column(name = "name", unique = true)
private String name;
#ManyToOne(optional = false, fetch = FetchType.EAGER)
#JoinColumn(name="partner_id", nullable = false)
private Partner partner;
...
}
Partner entity:
#Entity
#Table(name = "partners")
public class Partner {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#OneToMany(fetch = FetchType.LAZY, cascade={CascadeType.ALL}, mappedBy = "partner")
#OrderBy(value = "dateCreated desc")
private Set<Profile> profiles = new HashSet<Profile>();
#ManyToMany(fetch = FetchType.EAGER)
#OrderBy(value = "name asc")
#JoinTable(name = "partner_service",
joinColumns = { #JoinColumn(name = "partner_id") },
inverseJoinColumns = { #JoinColumn(name = "service_id") })
private Set<Service> services = new HashSet<Service>();
...
}
Service entity:
#Entity
#Table(name = "services")
public class Service {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "partner_service",
joinColumns = { #JoinColumn(name = "service_id") },
inverseJoinColumns = { #JoinColumn(name = "partner_id") })
private Set<Partner> partners = new HashSet<Partner>();
...
}
Here are my hibernate/datasource configurations:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="poolPreparedStatements" value="true" />
<property name="maxActive" value="20" />
<property name="initialSize" value="2" />
<property name="maxIdle" value="2" />
</bean>
<bean id="profileDAO" class="com.eniro.partnerapi.dao.impl.ProfileDAOHibernateImpl" />
<!-- Hibernate session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.eniro.partnerapi.model" />
<property name="hibernateProperties">
<props>
<prop key="dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">verify</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.jdbc.batch_size">30</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="dataSource" ref="dataSource" />
<property name="sessionFactory" ref="sessionFactory" />
</bean>
A Partner has a OneToMany to Profiles (and vice versa)
A Partner has a ManyToMany to Services
What I'm trying to achieve is that when I load a profile, I want its owning Partner to be loaded, and the Partner's Services at the same time. And yes, I want them to be eagerly loaded since they are rarely of great sets, and they are almost always needed all at the same time in this system.
An example scenario is:
Partner A has 3 profiles
Partner A has 5 services
The partners first Profile is fetched (profileX), at the same time the Partner and the Partner's Services are loaded.
Here is where my problem occurs (in the getProfile call in my DAO): Sometimes only the first service (based on id) is loaded from the database, and sometimes all 5 services are loaded.
What can be the cause of this? Anyone has any experience or anything for me to go on?
EDIT - adding additional info
We are using:
Hibernate 3.6.7.Final
MySQL connector 5.1.16
Spring 3.0.5.RELEASE
Quartz 1.6.1
MySQL 5.1.x
Tomcat 6.33
In a distributed environment where the application is run on two separate servers.
Alright, we managed to finally find the problem. It turns out it's not necessarily Hibernates fault.
We have a Quartz scheduler which was handling jobs on the side. The problem occurred once the scheduler (org.springframework.scheduling.quartz.SchedulerFactoryBean) started up. This is fine. However, we have two instances of the same application running in production, so the scheduler was using the database to synchronize between the two applications to keep a job from running at the same time from two instances.
However, this Quartz scheduler was communicating with the database in his own way (didn't find any code for it), which lead to clashes between Hibernates and Quartzs connections and thus giving the strange loading behaviour from the DAOs.
What exactly happened I can't say in detail, but we removed the DB dependency of Quartz and just used namespace to handle all jobs. After that, the problem was gone.
Warning to people using Hibernate/JDBC and Quartz scheduling between distributed applications: Be careful with how the components handle connections to the database.
Related
I have User class and BattleReportILogItem class. This class (User, BattleReportILogItem) are #Entity.
User have 0..N BattleReportILogItem.
USER
#Entity
#Table(name = DomainConstant.TABLE_USER)
public class User implements Serializable {
#Id
#Column(name = DomainConstant.DOMAIN_USER_ID)
#GeneratedValue
private Long userId;
#ManyToMany(cascade = {CascadeType.ALL})
#JoinTable(name = DomainConstant.VIEW_USER_BATTLE_LOGS, joinColumns = {
#JoinColumn(name = DomainConstant.DOMAIN_USER_ID)}, inverseJoinColumns = {
#JoinColumn(name = DomainConstant.DOMAIN_BATTLE_REPORT_ID)})
private Set<BattleReportILogItem> setOfBattleLogs = new HashSet<>();
....(other stuff, get and set methods...)
BattleReportILogItem
#Entity
#Table(name = DomainConstant.TABLE_BATTLE_REPORT)
public class BattleReportILogItem implements Serializable {
#Id
#GeneratedValue
#Column(name = DomainConstant.DOMAIN_BATTLE_REPORT_ID)
private Long BattleReportILogItemId;
#ManyToMany(mappedBy = "setOfBattleLogs")
private Set<User> setOfBattleLogs = new HashSet<>();
....(other stuff, get and set methods...)
The problem is, that I load User program loads all data in private Set<BattleReportILogItem> setOfBattleLogs = new HashSet<>();. This mean 1 000 000 000 items in my set setOfBattleLogs. I don't want load data to this set. For load data i have BattleReportLogItemDao DAO.
Is there any solution how to NOT LOAD DATA to my set?
I hope, you understand me... :-))
Thank you for your help.
EDIT persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="com.donutek" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/db"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="hibernate.validator.apply_to_ddl" value="true" />
<property name="connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"/>
<property name="hibernate.c3p0.min_size" value="5"/>
<property name="hibernate.c3p0.max_size" value="20"/>
<property name="hibernate.c3p0.timeout" value="300"/>
<property name="hibernate.c3p0.max_statements" value="50"/>
<property name="hibernate.c3p0.idle_test_period" value="300"/>
</properties>
</persistence-unit>
</persistence>
EDIT 2:
For load user I am using the code:
#Override
public User findByEmail(String email) {
TypedQuery<User> q = em.createQuery("SELECT u FROM " + User.class.getSimpleName() + " u WHERE u.email = :uemail", User.class);
q.setParameter("uemail", email);
try {
return q.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
You can use the parameter fetchtype Lazy. Now your strategy seems to be Eager.
I want insert some data in one of my table, and I get next exception:
`java.sql.SQLException: ORA-02289: sequence does not exist`
Let's me to show my code. I have next classes:
#Entity
#Table(name="role")
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="role_seq_gen")
#SequenceGenerator(name="role_seq_gen", sequenceName="ROLE_SEQ")
private Long roleId;
#Column(name="role", unique=true)
private String role;
#ManyToMany(mappedBy = "roles")
private List<Tipster> tipsters;
// + getters and setters
}
#Entity
#Table(name="tipster")
public class Tipster implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="tipster_id_seq")
#SequenceGenerator(name="tipster_id_seq", sequenceName="tipster_id_seq")
#Column(name="tipsterId")
private Long tipsterId;
#NotEmpty
#Column(name="username", unique=true)
private String username;
#NotEmpty
#Column(name="email", unique=true)
private String email;
#NotEmpty
#Column(name="password", unique=true)
private String password;
#Column(name="active")
private int active;
#ManyToMany
#JoinTable
private List<Role> roles;
//+ getters and setters
}
This is a part of my application context code:
<context:annotation-config />
<task:annotation-driven />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<jpa:repositories base-package="com.gab.gsn.repository" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521/XE" />
<property name="username" value="gabrieltifui" />
<property name="password" value="123321" />
</bean>
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="emf">
<property name="packagesToScan" value="com.gab.gsn.entity" />
<property name="dataSource" ref="dataSource" />
<property name="jpaProperties">
<props>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
</props>
</property>
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
</property>
</bean>
Now, I try to insert a row in my Role table with this method:
#PostConstruct
public void initDb(){
Role role = new Role();
role.setRole("User");
roleRepository.save(role);
}
When I my app on my Apache Server I get next exception:
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:123)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:89)
at org.hibernate.id.SequenceGenerator.generateHolder(SequenceGenerator.java:122)
at org.hibernate.id.SequenceGenerator.generate(SequenceGenerator.java:115)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:117)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
... 57 more
Caused by: java.sql.SQLException: ORA-02289: sequence does not exist
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:113)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:754)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:219)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:813)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1051)
at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:854)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1156)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3415)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3460)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:96)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:80)
... 68 more
It seems like I don't create the ROLE_SEQ sequence, but I know that Hibernate should create it automatically. Who can explain me why I get this exception?
It could be a problem related with your permissions, first execute the next statement select * from all_sequences where sequence_name = 'YOUR_SEQUENCE' ; If the sequence exists you only have to grant the permission to the user that you are using in your application. use grant select on YOUR_SEQUENCE to YOUR_USER; to fix your problem.
I use hibernate 4, spring 4, and I want to use #Transaction annotation, but it doesn't work.
The user object still saved on sqlServer.
Any idea what I'm doing wrong?
[applicationContext.xml]
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="SpringDAO"/>
<context:component-scan base-package="SpringTest"/>
<context:component-scan base-package="service"/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation">
<value>hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.generate_statistics">true</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.microsoft.sqlserver.jdbc.SQLServerDriver</value>
</property>
<property name="url">
<value>jdbc:sqlserver://127.0.0.1:1433;databaseName=test</value>
</property>
<property name="username">
<value>XXX</value>
</property>
<property name="password">
<value>XXX</value>
</property>
</bean>
[hibernate.cfg.xml]
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping class="SpringDAO.User" />
</session-factory>
</hibernate-configuration>
package SpringDAO;
#Repository("UserDAO3")
public class UserDAO3 {
SessionFactory sessionFactory;
#Autowired
public void setSessionFactory(SessionFactory value){
this.sessionFactory = value;
}
public SessionFactory getSessionFactory(){
return this.sessionFactory;
}
#Transactional(readOnly = true)
public boolean insert(Object user){
Session sess = this.sessionFactory.getCurrentSession();
sess.save(user);
return true;
}
}
package service;
#Service("UserService")
public class UserService {
public boolean addAction(User user){
boolean result = true;
UserDAO3 dao = (UserDAO3)SpringUtil.getBean("UserDAO3");
List<User> users = dao.searchAllUser();
for(User selectedUser : users){
if(selectedUser.getName().equals(user.getName())){
result = false;
break;
}
}
result = dao.insert(user);
return result;
}
}
From the docs,
This just
serves as a hint for the actual transaction subsystem; it will not
necessarily cause failure of write access attempts. A transaction
manager which cannot interpret the read-only hint will not throw an
exception when asked for a read-only transaction.
Whether the isolation level of the transaction can change depends on the implementation. Depending on the driver different things might occur, no guarantees, it does not enforce the failure.
POJO:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Integer id;
Modification:
#Id
#Column(name = "id")
private Integer id;
It works after eliminating #GeneratedValue(strategy = GenerationType.AUTO)
have a look at #Transactional read-only flag pitfalls on ibm.com, the explanation there is really great. Your question is answered there.
Here is my jpaContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config />
<context:component-scan base-package="com.pluralsight"/>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="punit"></property>
<property name="dataSource" ref="dataSource"></property>
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"></property>
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.dialect"
value="org.hibernate.dialect.MySQL5InnoDBDialect">
</entry>
<entry key="hibernate.hbm2ddl.auto" value="none"></entry>
<entry key="hibernate.format_sql" value="true"></entry>
</map>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory">
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="com.microsoft.sqlserver.jdbc.SQLServerDriver">
</property>
<property name="url"
value="jdbc:sqlserver://123.123.123.123:1433;databaseName=WikiGenome">
</property>
<property name="username" value="xxx"></property>
<property name="password" value="xxx"></property>
</bean>
</beans>
Here is my Disease.java:
#Entity
#Table(name="Disease")
public class Disease {
#Id
#GeneratedValue
#Column(name="DiseaseID")
public int DiseaseID;
#Column(name="Name")
public String Name;
}
Here is my another class:
#Entity
#Table(name="ChrPosDisease")
public class ChrPosDisease implements Serializable{
#Id
#Column(name="chr")
public String chr;
#Id
#Column(name="pos")
public int pos;
#Id
#Column(name="DiseaseID")
public int diseaseID;
}
I am new to hibernate and spring mvc framework and I just follows the guide in the tutorials.
I can query the result by using:
#SuppressWarnings({ "unchecked"})
public List getDiseaseByName(String name) {
Query query = em.createQuery("Select d From Disease d Where d.Name=?1").setParameter(1,name);
List diseaseList=query.getResultList();
return diseaseList;
}
However, when I join two table by DiseaseID, it gives following error.
java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Path expected for join! [Select d From cuhk.cse.fyp.model.Disease d JOIN ChrPosDisease c Where d.DiseaseID=c.DiseaseID AND d.Name=?1]
I don't got the error when querying the result with one table only.
Here is the code that I used to join that two table:
#SuppressWarnings({ "unchecked"})
public List getJoinDiseaseByName(String name) {
Query query = em.createQuery("Select d From Disease d JOIN ChrPosDisease c Where d.DiseaseID=c.DiseaseID AND d.Name=?1").setParameter(1,name);
List diseaseList=query.getResultList();
return diseaseList;
}
What's wrong?
Thanks for help.
Supplementary:
Updated ChrPosDisease
#SuppressWarnings("serial")
#Entity
#Table(name="ChrPosDisease")
public class ChrPosDisease implements Serializable{
#Id
#Column(name="chr")
public String chr;
#Id
#Column(name="pos")
public int pos;
#Column(name="DiseaseID")
public int diseaseID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="DiseaseID",nullable=false)
private Disease disease;
}
Updated Disease:
#SuppressWarnings("serial")
#Entity
#Table(name="Disease")
public class Disease implements Serializable{
#Id
#GeneratedValue
#Column(name="DiseaseID")
public int DiseaseID;
#Column(name="Name")
public String Name;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "ChrPosDisease")
private Set<ChrPosDisease> chrPosDisease = new HashSet<ChrPosDisease>();
}
I used above entity and there is exception in deploying.
Do I need to add anything else?
I think you should not use d.ChrPosDisease instead use just ChrPosDisease as d is an alias for only Disease entity.
and it should work.
let me know if it doesn't work.
You should have mapping entry as:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "disease")
private Set<ChrPosDisease> chrPosDisease = new HashSet<ChrPosDisease>();
mappedBy attribute notifies that the field is mapped by that particular entity property. So, this property should be the one on which connects entity on ManyToOne side.
Here Disease has many ChrPosDisease. And ChrPosDisease has one Disease. So mapped by column should be the one by which OneToMany field is bound with property on ManyToOne side.
I'm trying to get EHCache working within my app. First thing I did was adding maven dependency:
pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>${hibernate-version}</version>
</dependency>
So far so good, now within my application root-context.xml (SessionFactory is defiend in roout because of OpenSessionInView filter) I added MBean for Hibernate statistics from jConsole and full definition of my sessionFactory:
root-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="jmxExporter"
class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="Hibernate:type=statistics">
<ref local="statisticsBean"/>
</entry>
</map>
</property>
</bean>
<bean id="statisticsBean" class="org.hibernate.jmx.StatisticsService">
<property name="statisticsEnabled" value="true"/>
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="namingStrategy" class="com.execon.OracleNamingStrategy"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="oracle.jdbc.OracleDriver"/>
<property name="jdbcUrl" value="jdbc:oracle:thin:#127.0.0.1:1521:orcl"/>
<property name="user" value="xxx"/>
<property name="password" value="xxx"/>
<property name="maxPoolSize" value="10"/>
<property name="maxStatements" value="0"/>
<property name="minPoolSize" value="5"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="namingStrategy" ref="namingStrategy"/>
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="packagesToScan" value="com.execon.models"/>
</bean>
</beans>
Time to define hibernate.cfg.xml and ehcache file, so here they are:
hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</property>
<property name="hibernate.generate_statistics">true</property>
</session-factory>
</hibernate-configuration>
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<defaultCache
eternal="false"
maxElementsInMemory="1000"
maxElementsOnDisk="10000"
overflowToDisk="true"
diskPersistent="true"
timeToLiveSeconds="300"
/>
</ehcache>
Everything is working great, so now its time to define some Service to test cache, so I did:
#Service
#Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
#Transactional(readOnly = true)
public class MyService
{
#Autowired
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public List<SettlementModelGroup> getModelGroups()
{
List<SettlementModelGroup> list = new ArrayList<SettlementModelGroup>();
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery( "from SettlementModelGroup" );
list.addAll( query.list() );
return list;
}
}
As you can see, this basic method alwas returns me same list. So I'm checking hibernate statistics and:
secondLevelCacheHitCount 0
secondLevelCacheMissCount 0
secondLevelCachePutCount 0
Rest of the statistics on screen:
Link if too small: http://s11.postimage.org/yfg9h6m83/image.jpg
So whats wrong, did I miss something (obvious)? Or am I going completly wrong way?
EDIT
SettlementModelGroup Entity (tried also CacheConcurrencyStrategy.READ_WRITE)
#Entity
#Table(name = "MODEL_GROUP")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public class SettlementModelGroup implements Serializable
{
#Id
#GeneratedValue(generator = "MODEL_GROUP_SEQ", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "MODEL_GROUP_SEQ", sequenceName = "SEQ_MODEL_GROUP_MODEL_GROUP_ID")
#Column(name = "MODEL_GROUP_ID", nullable = false)
private Integer modelId;
#Column(name = "NAME", nullable = false)
private String modelGroupName;
#Column(name = "DESCRIPTION", nullable = false)
private String modelGroupDescription;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "MODEL_GROUP_TYPE_ID", nullable = false)
private SettlementModelGroupType settlementModelGroupType;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PERIOD_TYPE_ID", nullable = false)
private PeriodType periodType;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "DOMAIN_ID")
private Domain domain;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "OWNER_ID", nullable = false)
private User user;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "modelId")
#Cascade(CascadeType.ALL)
private List<SettlementModel> settlementModels;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "STATUS_ID")
private Status status;
//getters and setters here
}
Put #Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) on SettlementModelGroup (your domain entity) not the service method.
Also see this link. Depending on your version of EhCache (2.4.3.?) you might have to use CacheConcurrencyStrategy.READ_WRITE.