I'm having trouble with hibernate not able to open a connection. I have a DAO:
public class MyDao extends HibernateDaoSupport
{
DataSource dataSource;
public void setDataSource(DataSource dataSource)
{
this.dataSource = dataSource;
}
public MyPOJO findByQuery(int hour)
{
Query query = this.getSession().createSQLQuery(
"SELECT * FROM MyPOJO WHERE someDate >= DATE_SUB(now(), INTERVAL ? HOUR)")
.addEntity(MyPOJO.class);
List<MyPOJO> results = query.setInteger(0, hours).list();
return results;
}
}
and then in a test case call findByQuery(1) 8 times, it works, but if I call a 9th time it fails with:
org.hibernate.exception.GenericJDBCException: Cannot open connection
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:29)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:426)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:144)
at org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java:139)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1547)
at org.hibernate.loader.Loader.doQuery(Loader.java:673)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.doList(Loader.java:2213)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2104)
at org.hibernate.loader.Loader.list(Loader.java:2099)
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:289)
at org.hibernate.impl.SessionImpl.listCustomQuery(SessionImpl.java:1695)
at org.hibernate.impl.AbstractSessionImpl.list(AbstractSessionImpl.java:142)
at org.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:152)
Caused by: org.apache.commons.dbcp.SQLNestedException: Could not retrieve connection info from pool
at org.apache.commons.dbcp.datasources.SharedPoolDataSource.getPooledConnectionAndInfo(SharedPoolDataSource.java:169)
at org.apache.commons.dbcp.datasources.InstanceKeyDataSource.getConnection(InstanceKeyDataSource.java:631)
at org.apache.commons.dbcp.datasources.InstanceKeyDataSource.getConnection(InstanceKeyDataSource.java:615)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:81)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:423)
... 35 more
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
at org.apache.commons.pool.impl.GenericKeyedObjectPool.borrowObject(GenericKeyedObjectPool.java:827)
at org.apache.commons.dbcp.datasources.SharedPoolDataSource.getPooledConnectionAndInfo(SharedPoolDataSource.java:165)
... 39 more
This is what my hibernate properties look like:
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQL5Dialect
</prop>
<prop key="hibernate.current_session_context_class">
thread
</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.use_sql_comments">false</prop>
<prop key="hibernate.jdbc.use_get_generated_keys">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</prop>
<prop key="hibernate.connection.release_mode">auto</prop>
</props>
</property>
If I change the release_mode to 'after_statement' (ala http://docs.jboss.org/hibernate/stable/core/reference/en/html_single/#transactions-connection-release) it will work, but I don't understand that and feel like that is just a band-aid for something bigger that I am doing wrong.
I've also tried to flush and close the this.getSession() with no luck either. I can see the close() gets called AFTER all of the calls to findByQuery(1) have completed.
This is on Hibernate 3.2.6, Spring 3.0 and MySQL 5.1.
Let me know what more information I can provide.
Javadoc for HibernateDaoSupport.getSession() says:
Note that this is not meant to be
invoked from HibernateTemplate code
but rather just in plain Hibernate
code. Either rely on a thread-bound
Session or use it in combination with
releaseSession(org.hibernate.Session).
So, the session obtained via getSession() should be released via releaseSession():
public MyPOJO findByQuery(int hour)
{
Session s = null;
try {
s = this.getSession();
Query query = s.createSQLQuery(
"SELECT * FROM MyPOJO WHERE someDate >= DATE_SUB(now(), INTERVAL ? HOUR)")
.addEntity(MyPOJO.class);
List<MyPOJO> results = query.setInteger(0, hours).list();
return results;
} finally {
if (s != null) this.releaseSession(s);
}
}
But the better way to deal with session is to use a HibernateCallback:
public MyPOJO findByQuery(int hour)
{
return this.getHibernateTemplate().executeFind(new HibernateCallback<List<MyPOJO>>() {
List<MyPOJO> doInHibernate(org.hibernate.Session session) {
Query query = session.createSQLQuery(
"SELECT * FROM MyPOJO WHERE someDate >= DATE_SUB(now(), INTERVAL ? HOUR)")
.addEntity(MyPOJO.class);
return query.setInteger(0, hours).list();
}
});
}
I solved the same problem by updating the mysql-connector-java-5.1.23-bin.jar file.
Related
I have started working on an application which uses spring, hibernate, JPA, SOAP webservices. Now there is a requirement that certain queries have to be run in a transaction. If any one fails, entire transaction should rollback.
The code in the dao layer is as follows :
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;
import org.hibernate.Session;
public class BillDAOImpl implements BillDao{
#PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager em;
public boolean processBills() throws Exception{
EntityTransaction tx = null;
Session session = null;
try{
session = em.unwrap(Session.class);
tx = em.getTransaction();
Bill bill = em.find(Bill.class, billId);
//session.beginTransaction();
tx.begin();
...
...
em.persist(bill);
...
...
em.merge(<other object>);
...
...
//session.getTransaction().commit();
tx.commit();
} catch(){
}
}
}
When it executes tx = em.getTransaction(), it gives following error :
java.lang.IllegalStateException: Cannot execute getTransaction() on a container-managed EntityManager
The other transaction related properties are as follows :
<bean id="tuneEntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:persistenceXmlLocation="classpath*:META-INF/tune-persistence.xml"
p:persistenceUnitName="tunePersistenceUnit" p:loadTimeWeaver-ref="loadTimeWeaver"
p:jpaVendorAdapter-ref="jpaVendorAdapter" p:jpaDialect-ref="jpaDialect"
p:dataSource-ref="tuneDbDataSource">
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.BTMTransactionManagerLookup
</prop>
<prop key="net.sf.ehcache.configurationResourceName">/${tune-db.ehcache.config.file}</prop>
<prop key="hibernate.transaction.flush_before_completion">false</prop>
<prop key="hibernate.default_schema">${tune-db.schema}</prop>
<prop key="org.hibernate.envers.default_schema">${tune-db.schema}</prop>
<prop key="javax.persistence.validation.mode">${tune-db.data.validation}</prop>
<prop key="hibernate.connection.isolation">3</prop>
<prop key="hibernate.connection.release_mode">auto</prop>
<prop key="hibernate.show_sql">${tune-db.hibernate.show-sql}</prop>
<prop key="hibernate.format_sql">${tune-db.hibernate.format-sql}</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="tuneEntityManagerFactory" />
</bean>
When I use session.beginTransaction() and session.getTransaction().commit(), it works correctly.
However I want to replace it with transaction from entityManager. Then what should be done?
Try injecting EntityManagerFactory and then creating the EntityManager manually:
#PersistenceUnit
private EntityManagerFactory entityManagerFactory;
public boolean processBills() throws Exception{
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction tx = null;
Session session = null;
try{
session = em.unwrap(Session.class);
tx = em.getTransaction();
The EntityManager instance returned by #PersistenceContext is always a container managed EntityManager. And container managed EntityManager are always JTA EntityManagers and hence their lifecycle is managed by the container. I guess now it makes sense as to why it is illegal to call getTransaction() on them.This might help
The add a hibernate.jta.allowTransactionAccess property with the value true and you should be allowed to use it manually. Though it's not a good practice to mix your strategies, having some code managed by JTA, some manually.
#Transactional annotation will do exactly what you need.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#transaction-declarative-annotations
I repurposed an existing hibernate-spring project and upgraded to Hibernate 4 and Spring 4 and added multiple datasources using multitenancy. The application starts fine, the datasources are being read in using the MultiTenantDataSourceLookup class. When setting the new tenant, the tenant is resolved but then I get the nullpointerexception on line 41 of MultiTenantConnectionProviderImpl(See comment for line). I'm also using GenericHibernateDAO if that helps. I can post that code by request. I'm new to spring so the problem may be a very simple one. However, if more code is needed to help me, I will be happy to share more as I troubleshoot and research the problem myself. Any help will be greatly appreciated. Thanks. Here is the full stack trace: http://pastebin.com/LjyhTwvY
MultiTenantConnectionProviderImpl.java
public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl
{
#Autowired
private DataSource defaultDataSource;
#Autowired
private DataSourceLookup dataSourceLookup;
/**
* Select datasources in situations where not tenantId is used (e.g. startup processing).
*/
#Override
protected DataSource selectAnyDataSource() {
return defaultDataSource;
}
/**
* Obtains a DataSource based on tenantId
*/
#Override
protected DataSource selectDataSource(String tenantIdentifier) {
//Below is line 41 where the nullpointerexeption is occurring
DataSource ds = dataSourceLookup.getDataSource(tenantIdentifier);
return ds;
}
}
CurrentTenantIdentifierResolverImpl.java
public class CurrentTenantIdentifierResolverImpl implements CurrentTenantIdentifierResolver {
private static final String KEY_TENANTID_SESSION = "hibernate.tenant_identifier_resolver";
private static final String DEFAULT_TENANTID = "customer1";
public String resolveCurrentTenantIdentifier() {
String tenant = resolveTenantByHttpSession();
System.out.println("Tenant resolved: " + tenant);
return tenant;
}
/**
* Get tenantId in the session attribute KEY_TENANTID_SESSION
* #return TenantId on KEY_TENANTID_SESSION
*/
public String resolveTenantByHttpSession()
{
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//If session attribute exists returns tenantId saved on the session
if(attr != null){
HttpSession session = attr.getRequest().getSession(false); // true == allow create
if(session != null){
String tenant = (String) session.getAttribute(KEY_TENANTID_SESSION);
if(tenant != null){
return tenant;
}
}
}
//otherwise return default tenant
return DEFAULT_TENANTID;
}
public boolean validateExistingCurrentSessions() {
return true;
}
}
Context.xml
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<bean id="multitenancyConnectionProvider"
class="com.github.elizabetht.util.MultiTenantConnectionProviderImpl"/>
<bean id="dataSourceLookup"
class="com.github.elizabetht.util.MultiTenantDataSourceLookup"/>
<bean id="tenantResolver"
class="com.github.elizabetht.util.CurrentTenantIdentifierResolverImpl"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="packagesToScan">
<list>
<value>com.github.elizabetht.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
<prop key="hibernate.jdbc.lob.non_contextual_creation">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.multiTenancy">DATABASE</prop>
<prop key="hibernate.multi_tenant_connection_provider">com.github.elizabetht.util.MultiTenantConnectionProviderImpl</prop>
<prop key="hibernate.tenant_identifier_resolver">com.github.elizabetht.util.CurrentTenantIdentifierResolverImpl</prop>
</props>
</property>
</bean>
<bean id="defaultDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/studentEnrollment" />
<property name="username" value="springy" />
<property name="password" value="pass" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="autodetectDataSource" value="false"/>
</bean>
OUTPUT
Tenant resolved: customer1
Feb 25, 2017 1:34:31 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [studentHibernateServlet] in context with path [/StudentEnrollmentWithSpring] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at com.github.elizabetht.util.MultiTenantConnectionProviderImpl.selectDataSource(MultiTenantConnectionProviderImpl.java:41)
at org.hibernate.engine.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl.getConnection(AbstractDataSourceBasedMultiTenantConnectionProviderImpl.java:52)
at org.hibernate.internal.AbstractSessionImpl$ContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:423)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:228)
I changed my hibernate properties to the following and everything works now:
<property name="hibernateProperties">
<map>
<entry key="hibernate.multi_tenant_connection_provider" value-ref="multitenancyConnectionProvider"/>
<entry key="hibernate.tenant_identifier_resolver" value-ref="tenantResolver"/>
<entry key="hibernate.multiTenancy" value="DATABASE"/>
</map>
</property>
I have a class in java with two more methods similar to the one here.
public Object noOfEmployees() {
List<Employee> emp = null;
String u = user.getUserName();
if ("user1".equals(u)) {
Query query = getHibernateTemplate().getSessionFactory().openSession()
.createSQLQuery("select * from employee where job='System Analyst'")
.addEntity(EMPLOYEE.class);
emp = query.list();
getHibernateTemplate().getSessionFactory().openSession().close();
} else if ("user2".equals(u)) {
Query query = getHibernateTemplate().getSessionFactory().openSession()
.createSQLQuery("select * from employee where job='DBA'")
.addEntity(EMPLOYEE.class);
emp = query.list();
getHibernateTemplate().getSessionFactory().openSession().close();
}
return emp.size();
}
When I ran the application, this is how I got the output:
Logged in as 'user2'
Hibernate: select * from employee where job='DBA'
Hibernate: select * from employee where job='DBA' and rank='2'
Hibernate: select * from employee where present='yes'
Logged in as 'user1'
Hibernate: select * from employee where job='System Analyst'
Hibernate: select * from employee where job='System Analyst' and rank='3'
Hibernate: select * from employee where present='yes'
Again, logged in as 'user2', first two methods get executed.
Hibernate: select * from employee where job='DBA'
Hibernate: select * from employee where job='DBA' and rank='2'
When I logged in as any user, this time even the first method did not get executed.
I have noticed that the code gets stuck when query.list() is encountered. I know that using hibernateTemplate is not recommended but the entire application is written using it. I have only started to learn about spring and hibernate. I will start making changes once I get comfortable with those.
Any suggestions related to the performance of query.list() and ways to improve the code are more than welcome.
Thank you!
Your code is flawed on many levels... For starters you shouldn't be using HibernateTemplate unless you are in a very old application, else use a plain SessionFactory. See http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html#orm-hibernate-straight for more information.
Second when using Spring use Spring to manage your resources, i.e. Session in this case, or if you want to do it yourself at least manage it properly!.
So in short use a SessionFactory and use getCurrentSession instead of openSession. And use a proper query.
#Autowired
private SessionFactory sf;
#Transactional
public Long noOfEmployees() {
final String query = "select count(*) from employee where job=:job";
Query q = sf.getCurrentSession().createSQLQuery(query);
if ("user1".equals(u)) {
q.setParameter("job", "System Analyst");
} else if ("user2".equals(u) ) {
q.setParameter("job", "DBA");
}
return (Long) query.uniqueResult();
}
The #Transactional will make spring manage the resources, assuming you have <tx:annotation-driven /> in your context and properly added the HibernateTransactionManager.
The problem, obviously, with this code
Query query = getHibernateTemplate().getSessionFactory().openSession().
...
getHibernateTemplate().getSessionFactory().openSession().close();
With this getHibernateTemplate().getSessionFactory().openSession().close() you get a new session and close it!
You should use HQL
Query query = session.createQuery("from Employee where job='System Analyst'");
List<Employee> emp = query.list();
And the way you use Hibernate Template is entirely incorrect.
Refer how to use it
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/classic-spring.html
An example
public class ProductDaoImpl {
private HibernateTemplate hibernateTemplate;
public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
public Collection loadProductsByCategory(final String category) throws DataAccessException {
return this.hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) {
Criteria criteria = session.createCriteria(Product.class);
criteria.add(Expression.eq("category", category));
criteria.setMaxResults(6);
return criteria.list();
}
};
}
}
I have tried to change my flawed-on-many-levels code to some extent. All thanks to #M.Deinum and #v.ladynev for their swift responses.
Given below are only snippets where changes to move from HibernateTemplate to SessionFactory are mentioned:
//IndexService
#Transactional
public class IndexService {
User user;
SessionFactory sf;
public IndexService(User user, SessionFactory sf) {
this.user = user;
this.sf = sf;
}
//This method is used to get the number of employees based on users.
public Object noOfEmployees() {
String u = user.getUserName();
final String query = "select count(*) from employee where job=:job";
Query q = sf.getCurrentSession().createSQLQuery(query);
if ("user1".equals(u)) {
q.setParameter("job", "System Analyst");
} else if ("user2".equals(u) ) {
q.setParameter("job", "DBA");
}
return q.uniqueResult();
}
--------------------------------------------------------------------------------------
//Index
#Controller
#Transactional
public class Index {
#Autowired
User user;
#Autowired
SessionFactory sf;
#RequestMapping("/index")
public ModelAndView getIndex() {
System.out.println("user.getUserName() In Index = " + user.getUserName());
ModelAndView modelAndView = new ModelAndView("index");
IndexService indexService = new IndexService(user, sf);
modelAndView.addObject("noOfEmployees", indexService.noOfEmployees());
return modelAndView;
}
}
--------------------------------------------------------------------------------------
//spring-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="basicDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url"
value="jdbc:mysql://localhost/database_name"></property>
<property name="username" value="user"></property>
<property name="password" value="password"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="basicDataSource"></property>
<property name="mappingResources" value="myBeans.hbm.xml" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
Issues that I came across while changing from HibernateTemplate to SessionFactory:
1.NullPointerException for SessionFactory
In index class,
#Autowired
SessionFactory sf;
and passed it as an argument.
IndexService indexService = new IndexService(user, sf);
2.No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
I put #Transactional above Index also. It is the controller in my application.
Thank you once again #M.Deinum and #v.ladynev!
I am trying to implement Entity Auditing functionality using spring-data-envers. The problem is my company is still using Hibernate 3, and it looks like spring-data-envers only work with Hibernate 4. The following are the error I got:
org.springframework.orm.jpa.JpaSystemException: You need to install the org.hibernate.envers.event.AuditEventListener class as post insert, update and delete event listener.; nested exception is org.hibernate.envers.exception.AuditException: You need to install the org.hibernate.envers.event.AuditEventListener class as post insert, update and delete event listener.
at org.hibernate.envers.AuditReaderFactory.get(AuditReaderFactory.java:71)
at org.hibernate.envers.AuditReaderFactory.get(AuditReaderFactory.java:85)
at org.springframework.data.envers.repository.support.EnversRevisionRepositoryImpl.findRevisions(EnversRevisionRepositoryImpl.java:127)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:414)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:399)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:371)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy30.findRevisions(Unknown Source)
at org.springframework.data.envers.repository.support.RepositoryIntegrationTest.returnsEmptyRevisionsForUnrevisionedEntity(RepositoryIntegrationTest.java:99)
Any help is appreciated.
Try following configuration
in pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
<version>${hibernate.version}</version>
</dependency>
in spring-hibernate.xml ( or whatever name you gave )
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>com.yourpackage.model</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">replace_with_your_</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">${hibernate.show.sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format.sql}</prop>
<!-- Envers properties -->
<prop key="org.hibernate.envers.auditTablePrefix"/>
<prop key="org.hibernate.envers.auditTableSuffix">_HISTORY</prop>
</props>
</property>
Important line:
<prop key="org.hibernate.envers.auditTablePrefix"></prop>
<prop key="org.hibernate.envers.auditTableSuffix">_HISTORY</prop>
The suffix '_HISTORY' is the name you choose to give to database table that will hold different versions of you entity. And last one #Audited annotation, is placed on top of your entities that need to be audited.
#Entity
#Table(name = "user")
#Audited
public class User implements Serializable {}
Here is the Spring Java Config in my project that make the spring-data-envers works:
#Configuration
#EnableJpaRepositories(basePackages = "your.repository.package", repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
public class ServiceModelTestSpringConfig {
//.. Spring-JPA-Hibernate setup ..
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("your.entity.package");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
// dataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); // Use in-memory database
dataSource.setUrl("jdbc:h2:~/test/itdata;DB_CLOSE_DELAY=-1"); // Use file database
dataSource.setUsername("ying");
return dataSource;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.connection.autocommit", "false");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
// Hibernate Envers Event Listeners
properties.setProperty("hibernate.ejb.event.post-insert", "org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener");
properties.setProperty("hibernate.ejb.event.post-update", "org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener");
properties.setProperty("hibernate.ejb.event.post-delete", "org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener");
properties.setProperty("hibernate.ejb.event.pre-collection-update", "org.hibernate.envers.event.AuditEventListener");
properties.setProperty("hibernate.ejb.event.pre-collection-remove", "org.hibernate.envers.event.AuditEventListener");
properties.setProperty("hibernate.ejb.event.post-collection-recreate", "org.hibernate.envers.event.AuditEventListener");
return properties;
}
// .. EOF Spring-JPA-Hibernate setup ..
}
I am using hibernate with spring frame work and my beans are in singleton mode.did i supposed to close my session or no (because they are in singleton mode)?
the reality is that we got some problems on our server and too many connections problem
and i thought may be that is the problem.thanks.
this is my codes:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" scope = "singleton" >
<property name="dataSource" ref local="dataSource" property/>
<property name="packagesToScan" >
<value>Model.Entity</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.auto_close_session">false</prop>
</props>
</property>
and this is the way i use , i close all sessions after i used
#Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void updateDB() {
Session session = getSessionFactory().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
transaction.commit();
} catch (HibernateException e) {
transaction.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
If you configure the spring and hibernate configuration you don't need to close the connections and sessions, Spring will do that for you.
See this example http://howtodoinjava.com/2013/03/21/spring-3-and-hibernate-integration-tutorial-with-example/