【问题标题】:Spring Hibernate "You cannot commit during a managed transaction!"Spring Hibernate“您不能在托管事务期间提交!”
【发布时间】:2023-03-28 07:18:02
【问题描述】:

将我的应用程序从 JSF 1.2 升级到 JSF 2.1 后,尝试登录时出现以下 Spring Hibernate 异常:

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

这是我的 spring bean 配置:

    <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>

这里是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>

@Transactional 注释仅用于我的应用程序和单元测试中的一种方法,但不用于涉及应用程序登录部分的内容。

进一步调查我的异常,我从ironjacamar-jdbc-1.0.17 看到了在BaseWrapperManagedConnection 中引发异常的代码:

/**
    * 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);
               }
            }
         }
      }
   }

变量inManagedTransactionLocalManagedConnection 的begin 方法中从ironjacamar-jdbc-1.0.17 设置为true:

/**
    * {@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();
      }
   }

而这个inManagedTransaction 设置为false 的唯一地方是LocalManagedConnection commit()rollback() 方法:

/**
    * {@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();
      }
   }

我有两个 ManagedConnection 一个是 BaseWrapperManagedConnection 另一个是 LocalManagedConnection 并且我正在经历他们的两种提交方法是否正常?

我还读到 JBoss 也可以处理事务(容器管理事务)。 Spring 和 JBoss 是否都可能尝试处理我的会话和事务?

我使用的是 Hibernate 4.2 和 Spring 3.2.0。 其中大部分是经典配置,就像在网络上的许多教程中找到的一样,没什么特别的。使用此配置的应用程序使用 JSF 1.2 工作。 感谢您的任何建议,提示。

【问题讨论】:

  • 从堆栈跟踪来看,您自己打开和关闭会话,而不是让 spring 为您处理。我还想知道为什么你将经典的事务配置(xml 和切分)和@Transactional 混合在一起,在某些时候会咬你。 JSF 1.2 和 2.x 发生了很大变化,升级不仅仅是替换一个 jar,而是需要更多的工作(根据我的经验)。
  • 你怎么看我在使用 @Transactional ?实际上我没有使用这个注释,除了在我的测试中。
  • @M.Deinum,我如何检查自己是否打开/关闭会话?但我认为我的代码中并非如此,但也许 jsf 2.1 或 jboss seam 正在打开/关闭会话?
  • &lt;tx:annotation-driven /&gt;,这是一个相当大的赠品。你有一个ConnectionBean,它来自你自己的手,它对连接做了一些事情,因此我的建议是你可能正在用你不应该做的连接/会话自己做一些事情......
  • 另一件事是您为什么将 JBoss Seam 与 Spring 结合使用?通常,试图将 2 个框架组合在一起最终会发生冲突。

标签: java spring hibernate transactions jboss7.x


【解决方案1】:

您可能在 JBoss 中配置了一个 JTA 数据源,这是一个托管事务资源,然后您使用的是非 JTA HibernateTransactionManager

要修复它,您有两种选择:

  1. 您可以使用 RESOURCE_LOCAL 数据源并通过 JNDI 提供它
  2. 您保留 JTA 数据源并配置 Hibernate 以使用 Spring JtaTransactionManager 和实际的 Arjuna Transaction Manager

【讨论】:

  • 就是这个。 JBoss 默认配置为使用 JTA。现在已经修好了,谢谢大家。
【解决方案2】:

如果您的数据源使用 jta,则不得调用 transaction.begin 也不得提交容器调用的那些事务分界。 如果您的数据源使用 RESOURCE_LOCAL,您必须划分所有事务,甚至是只读事务。

【讨论】:

    猜你喜欢
    • 2015-09-26
    • 2015-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-20
    • 1970-01-01
    • 2015-11-09
    • 1970-01-01
    相关资源
    最近更新 更多