【发布时间】: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);
}
}
}
}
}
变量inManagedTransaction 在LocalManagedConnection 的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 正在打开/关闭会话?
-
有
<tx:annotation-driven />,这是一个相当大的赠品。你有一个ConnectionBean,它来自你自己的手,它对连接做了一些事情,因此我的建议是你可能正在用你不应该做的连接/会话自己做一些事情...... -
另一件事是您为什么将 JBoss Seam 与 Spring 结合使用?通常,试图将 2 个框架组合在一起最终会发生冲突。
标签: java spring hibernate transactions jboss7.x