0

Hibernate5 SessionImpl is not recognizing transaction started by JpaTransactionManager

I recently migrated a legacy java web application to spring-boot, Hibernate. Jersey was already used in legacy app, so continued with spring-boot-starter-jersey. So the stack is:

RestfulService(Jersey) -> Spring Service -> Hibernate DAO (legacy code).

Both Spring service and Hibernate DAOs are used through respective public interface and has @Transactional on public method of implementation class.

Hibernate DAO looks like:

@Repository public class UserDaoImpl implements UserDao {

@Autowired
@Qualifier("entityManagerFactory")
EntityManagerFactory entityManagerFactory;

public SessionFactory getSessionFactory() {
    return entityManagerFactory.unwrap(SessionFactory.class);
}

@Override
public User getUserByUserName(String userName) throws Exception {

    User user = null;
    Criteria criteria = getSessionFactory().getCurrentSession().createCriteria(User.class);
    criteria.add(Restrictions.eq("userName", userName));
    user = (User) criteria.uniqueResult();
    return user;
}

}

With JpaTransactionManager I was getting exception :

javax.persistence.TransactionRequiredException: no transaction is in progress.

javax.persistence.TransactionRequiredException: no transaction is in progress
    at org.hibernate.internal.SessionImpl.checkTransactionNeeded(SessionImpl.java:3505)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1427)
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1423)
    at org.springframework.orm.hibernate5.SessionFactoryUtils.flush(SessionFactoryUtils.java:147)
    at org.springframework.orm.hibernate5.SpringSessionSynchronization.beforeCommit(SpringSessionSynchronization.java:95)
    at org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCommit(TransactionSynchronizationUtils.java:96)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCommit(AbstractPlatformTransactionManager.java:922)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:730)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:532)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at com.iotu.serviceImpl.UserServiceImpl$$EnhancerBySpringCGLIB$$d0c10f8c.checkLoginDetails(<generated>)
    at com.iotu.webservices.UserWS.userAuthentication(UserWS.java:1467)
    at com.iotu.webservices.UserWS$$FastClassBySpringCGLIB$$66e6577d.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684)
    at com.iotu.webservices.UserWS$$EnhancerBySpringCGLIB$$99ca5efe.userAuthentication(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:76)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:148)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:191)

Switched to HibernateTransactionManager and Hibernate is able to recognize transaction in progress. No exception thrown.

@Configuration
@EnableJpaRepositories("com.app.repository")
public class AppConfiguration {

   @Bean
   public HibernateTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
       SessionFactory sf = entityManagerFactory.unwrap(SessionFactory.class);
      return new HibernateTransactionManager(sf);
   }

But it has a down side. For newer features i am using spring data repository. With HibernateTransactionManager, the JpaRepository's save method is NOT working on entity. Its not firing the update sql (No error on console). findXX methods are working fine.

@Repository
public interface LessonCategoryRepository extends JpaRepository<LessonCategory, Long> {

   public List<LessonCategory> findByCategoryAndLanguage(@Param("category") String category, @Param("language") String language);
} 

When I switch to JpaTransactionManager, updates through JpaRepository are working fine but start getting the javax.persistence.TransactionRequiredException: no transaction is in progress for services calls that use legacy DAO classes..

To summarize:

  • With HibernateTransactionManager: Hibernate5 recognizes current transaction but JpaRepository is not persisting data.
  • With JpaTransactionManager: Hibernate5 session does NOT recognizes current transaction but JpaRepository is persisting data.

Can I make JpaTransactionManager to work with existing hibernate DAO classes? Or can I make HibernateTransactionManager to work with JpaRepository? .. so that I can use legacy DAO classes as is but can continue using the JpaRepositories.

  • Have you set the `spring.jpa.properties.hibernate.current_session_context=org.springframework.orm.hibernate5.SpringSessionContext` in your `application.properties`. The class could be different, typed it from the top of my head. Also which hibernate version are you using? – M. Deinum Aug 09 '18 at 19:31
  • Yes it is set in application.properties. `spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext` Hibernate finds current Session and from there it chekcs for current transaction, which is not found. While debugging I found that JpaTransactionManager is begining the transaction which Hibernate5 is not finding and throws eror. – user1132809 Aug 10 '18 at 01:33
  • You haven't answered which hibernate version you are using. – M. Deinum Aug 10 '18 at 05:35
  • Fond a solution ... Do NOT use ` @Autowired @Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory; public Session getCurrentSession() { return entityManagerFactory.unwrap(SessionFactory.class).getCurrentSession(); }` More details at - https://stackoverflow.com/questions/50650041/spring-boot-hibernate-no-transaction-is-in-progress – user1132809 Aug 10 '18 at 12:33

0 Answers0