jerome
jerome

Reputation: 2089

Spring Hibernate "You cannot commit during a managed transaction!"

After upgrading my application from JSF 1.2 to JSF 2.1 I have the following Spring Hibernate exception when trying to login:

DEBUG,[interceptor.ExceptionInterceptor][],org.springframework.transaction.TransactionSystemException: Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: commit failed
    at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:472)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:392)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at myapp.aop.interceptor.MethodExceptionInterceptor.invoke(MethodExceptionInterceptor.java:21)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at myapp.aop.interceptor.SessionActivityInterceptor.invoke(SessionActivityInterceptor.java:47)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at com.sun.proxy.$Proxy121.endSession(Unknown Source)
    at myapp.web.action.connection.ConnectionBean.connect(ConnectionBean.java:100)
    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.jboss.seam.util.Reflections.invoke(Reflections.java:22)
    at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:32)
    at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56)
    at myapp.web.interceptor.ExceptionInterceptor.aroundInvoke(ExceptionInterceptor.java:42)
    at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
    at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:28)
    at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
    at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
    at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:44)
    at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
    at org.jboss.seam.core.SynchronizationInterceptor.aroundInvoke(SynchronizationInterceptor.java:35)
    at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
    at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107)
    at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:186)
    at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:104)
    at myapp.web.action.connection.ConnectionBean_$$_javassist_seam_2.connect(ConnectionBean_$$_javassist_seam_2.java)
    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.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:335)
    at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:348)
    at org.jboss.el.parser.AstPropertySuffix.invoke(AstPropertySuffix.java:58)
    at org.jboss.el.parser.AstValue.invoke(AstValue.java:96)
    at org.jboss.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276)
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
    at org.apache.myfaces.trinidad.component.MethodExpressionMethodBinding.invoke(MethodExpressionMethodBinding.java:46)
    at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:101)
    at org.apache.myfaces.trinidad.component.UIXCommand.broadcast(UIXCommand.java:190)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:786)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1251)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._invokeApplication(LifecycleImpl.java:1074)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._executePhase(LifecycleImpl.java:402)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:225)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:295)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
    at oracle.adfinternal.view.faces.webapp.rich.RegistrationFilter.doFilter(RegistrationFilter.java:105)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:502)
    at oracle.adfinternal.view.faces.activedata.AdsFilter.doFilter(AdsFilter.java:60)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:502)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl._doFilterImpl(TrinidadFilterImpl.java:327)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl.doFilter(TrinidadFilterImpl.java:229)
    at org.apache.myfaces.trinidad.webapp.TrinidadFilter.doFilter(TrinidadFilter.java:92)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:246)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
    at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at myapp.web.filter.SessionActivityFilter.doFilter(SessionActivityFilter.java:67)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
    at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
    at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:246)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:149)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:389)
    at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:145)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:336)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:653)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:920)
    at java.lang.Thread.run(Thread.java:724)
 Caused by: org.hibernate.TransactionException: commit failed
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:185)
    at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:468)
    ... 93 more
 Caused by: org.hibernate.TransactionException: unable to commit against JDBC connection
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(JdbcTransaction.java:116)
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:178)
    ... 94 more
 Caused by: java.sql.SQLException: You cannot commit during a managed transaction!
    at org.jboss.jca.adapters.jdbc.BaseWrapperManagedConnection.jdbcCommit(BaseWrapperManagedConnection.java:1052)
    at org.jboss.jca.adapters.jdbc.WrappedConnection.commit(WrappedConnection.java:757)
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(JdbcTransaction.java:112)
    ... 95 more

Here is my spring beans configuration :

    <bean id="parentSessionFactory" abstract="true">
        <property name="dataSource">
            <ref bean="myDS" />
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.connection.driver_class">
                    org.h2.Driver
                </prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
                <prop key="hibernate.cache.use_query_cache">true</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.use_structured_cache">true</prop>                            
            </props>
        </property>
    </bean>

    <bean id="myDS"
          class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:/myDS" />
    </bean>


    <bean id="sessionFactory" parent="parentSessionFactory"
      class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">   
      <property name="configLocation">
        <value>
            classpath:model/hibernate.cfg.xml
        </value>
      </property>

      <property name="hibernateProperties">
        <props merge="true">
            <prop key="hibernate.dialect">
                org.hibernate.dialect.H2Dialect
            </prop>    
        </props>        
      </property>
    </bean>

    <bean id="transactionManager"
      class="org.springframework.orm.hibernate4.HibernateTransactionManager">
      <property name="sessionFactory">
        <ref bean="sessionFactory"/>
      </property>
    </bean>


    <!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!-- the transactional semantics... -->
      <tx:attributes>
        <!-- all methods starting with 'get' are read-only -->
        <tx:method name="get*" read-only="true" />
        <tx:method name="find*" read-only="true" />
        <tx:method name="list*" read-only="true" />
        <tx:method name="read*" read-only="true" />
        <tx:method name="save*" read-only="false" isolation="READ_COMMITTED"/>
        <tx:method name="remove*" read-only="false" isolation="READ_COMMITTED"/>
        <tx:method name="refresh*" read-only="false" isolation="READ_COMMITTED"/>
        <tx:method name="delete*" read-only="false" isolation="READ_COMMITTED"/>
        <!-- other methods use the default transaction settings (see below) -->
        <tx:method name="*" />
      </tx:attributes>
    </tx:advice>
    <tx:annotation-driven transaction-manager="transactionManager"/>

<!-- ensure that the above transactional advice runs for any execution
    of an operation defined by the *Service interface -->
    <aop:config>
        <aop:pointcut id="serviceOperation"
                      expression="execution(* services..*Service*.*(..))" />
        <aop:pointcut id="daoOperation"
                      expression="execution(* dao..*Dao.*(..))" />


        <aop:advisor advice-ref="sessionActivityInterceptor"
                     pointcut-ref="serviceOperation" />         
        <aop:advisor advice-ref="exceptionInterceptor"
                     pointcut-ref="serviceOperation" />      -->
        <aop:advisor advice-ref="txAdvice"
                     pointcut-ref="serviceOperation" />
        <aop:advisor advice-ref="txAdvice"
                     pointcut-ref="daoOperation" />      
    </aop:config>

Here is the hibernate.cfg.xml:

<hibernate-configuration>
    <session-factory>

        <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
<!--        <property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</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>


        <!-- Several mapping classes here -->
    </session-factory>
</hibernate-configuration>

The @Transactional annotation is only used in one method in my application and in my unit tests, but is not used for what concerns the login part of the app.

Investigating my exception further I see the code that throw the exception in BaseWrapperManagedConnection from ironjacamar-jdbc-1.0.17 :

/**
    * JDBC commit
    * @exception SQLException Thrown if an error occurs
    */
   void jdbcCommit() throws SQLException
   {
      synchronized (stateLock)
      {
         if (inManagedTransaction)
            throw new SQLException("You cannot commit during a managed transaction!");

         if (jdbcAutoCommit)
            throw new SQLException("You cannot commit with autocommit set!");
      }
      con.commit();

      if (mcf.isJTA().booleanValue())
      {
         if (inLocalTransaction.getAndSet(false))
         {
            Collection<ConnectionEventListener> copy = null;
            synchronized (cels)
            {
               copy = new ArrayList<ConnectionEventListener>(cels);
            }

            ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.LOCAL_TRANSACTION_COMMITTED);

            for (Iterator<ConnectionEventListener> i = copy.iterator(); i.hasNext();)
            {
               ConnectionEventListener cel = i.next();
               try
               {
                  cel.localTransactionCommitted(ce);
               }
               catch (Throwable t)
               {
                  if (trace)
                     getLog().trace("Error notifying of connection committed for listener: " + cel, t);
               }
            }
         }
      }
   }

the variable inManagedTransaction is set to true in LocalManagedConnection begin method from ironjacamar-jdbc-1.0.17 :

/**
    * {@inheritDoc}
    */
   public void begin() throws ResourceException
   {
      lock();
      try
      {
         synchronized (stateLock)
         {
            if (!inManagedTransaction)
            {
               try
               {
                  if (underlyingAutoCommit)
                  {
                     underlyingAutoCommit = false;
                     con.setAutoCommit(false);
                  }
                  checkState();
                  inManagedTransaction = true;
               }
               catch (SQLException e)
               {
                  checkException(e);
               }
            }
            else
               throw new ResourceException("Trying to begin a nested local tx");
         }
      }
      finally
      {
         unlock();
      }
   }

And the only place where this inManagedTransaction is set to false is in LocalManagedConnection commit() or rollback() method :

/**
    * {@inheritDoc}
    */
   public void commit() throws ResourceException
   {
      lock();
      try
      {
         synchronized (stateLock)
         {
            if (inManagedTransaction)
               inManagedTransaction = false;
         }
         try
         {
            con.commit();
         }
         catch (SQLException e)
         {
            checkException(e);
         }
      }
      finally
      {
         unlock();
      }
   }

   /**
    * {@inheritDoc}
    */
   public void rollback() throws ResourceException
   {
      lock();
      try
      {
         synchronized (stateLock)
         {
            if (inManagedTransaction)
               inManagedTransaction = false;
         }
         try
         {
            con.rollback();
         }
         catch (SQLException e)
         {
            try
            {
               checkException(e);
            }
            catch (Exception e2)
            {
               // Ignore
            }
         }
      }
      finally
      {
         unlock();
      }
   }

Is it normal that I have two ManagedConnection one is BaseWrapperManagedConnection and the other LocalManagedConnection and that I'm going through both of their commit method ?

I have also read that JBoss could also take care of transactions (container managed transactions). Is it possible that both Spring and JBoss try to handle my sessions and transactions ?

I'm using Hibernate 4.2 and Spring 3.2.0. Most of it is classical configuration like found on many tutorials on the web nothing fancy. The application using this configuration was working using JSF 1.2. Thanks for any advices, hints.

Upvotes: 4

Views: 6726

Answers (2)

Vlad Mihalcea
Vlad Mihalcea

Reputation: 153800

You probably configured a JTA DataSource in JBoss, which is a managed transactional resource and then you are using a non-JTA HibernateTransactionManager.

To fix it, you have two options:

  1. You either use a RESOURCE_LOCAL DataSource and provide it via JNDI
  2. You keep the JTA DataSource and configure Hibernate to use the Spring JtaTransactionManager with the actual Arjuna Transaction Manager

Upvotes: 2

kamel2005
kamel2005

Reputation: 459

if your data source uses jta you must not call transaction.begin neither commit those transaction demarcation are called by the container. if your data source uses RESOURCE_LOCAL you have to demarcate all your transaction even read only ones.

Upvotes: 1

Related Questions