我们收到错误
org.springframework.transaction.IllegalTransactionStateException:找到预绑定的JDBC连接!如果告知要管理DataSource本身,HibernateTransactionManager不支持在DataSourceTransactionManager中运行。对于单个DataSource上的所有事务,建议使用单个HibernateTransactionManager,无论是Hibernate还是JDBC访问。
它发生的地方是我们覆盖事务管理器的地方,以便我们可以对doBegin,commit和rollback方法做出反应。但是,错误发生在doBegin中,我们称之为super.doBegin(),并且在我们的任何代码实际运行之前。当我们想要它时,错误也是非常间歇性和不合作的。
我在网上看到很多人建议这通常意味着您定义了两个交易管理器。我最初拒绝将此视为适用于我们,因为我们没有。我仔细检查过。但是,不是那么快,也许我这样做。虽然我们的战争中只有一个tx管理器,但是发生这种情况的应用程序......这个发生的唯一应用程序......是同一个EAR中的两场战争。每个都有自己定义的弹簧上下文,它是自己的txManager。他们可能有冲突吗?这可能是我们麻烦的根源吗?
更新 -
app-config.xml(至少可能是相关的部分......我留下了很多普通的bean定义)
<bean id="dataSource" name="enoteDataSource dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="resourceRef"><value>false</value></property>
<property name="jndiName">
<value>${ds.jndi}</value>
</property>
</bean>
<bean id="sessionFactory" name="sessionFactory enoteSessionFactory" class = "org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource"><ref local="dataSource" /></property>
<property name="packagesToScan">
<list>
<value>gov.usdoj.afms.enote.model.*</value>
</list>
</property>
<bean id="txManager" name="txManager transactionManager" class="gov.usdoj.afms.umc.utils.hibernate.AfmsHibernateTransactionManager">
<property name="sessionFactory" ref="enoteSessionFactory" />
</bean>
<!-- some of the transaction are controlled in code through annotation -->
<tx:annotation-driven transaction-manager="txManager"/>
<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txActionAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<tx:method name="deleteUser" propagation="REQUIRES_NEW" rollback-for="BOException" />
<tx:method name="*" propagation="REQUIRES_NEW" />
</tx:attributes>
</tx:advice>
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'fetch' are read-only -->
<tx:method name="fetch*" isolation="READ_UNCOMMITTED"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" rollback-for="Throwable" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor
pointcut="execution(* gov.usdoj.afms.umc.services.ActionPanelService.*(..))"
advice-ref="txActionAdvice"/>
<aop:advisor
pointcut="execution(* gov.usdoj.afms.umc.services.AccountInfoService.*(..))"
advice-ref="txAdvice"/>
<aop:advisor
pointcut="execution(* gov.usdoj.afms.umc.services.PersonalInfoService.*(..))"
advice-ref="txAdvice"/>
<aop:advisor
pointcut="execution(* gov.usdoj.afms.umc.services.CreateUserService.*(..))"
advice-ref="txAdvice"/>
<aop:advisor
pointcut="execution(* gov.usdoj.afms.umc.services.UM04Service.*(..))"
advice-ref="txAdvice"/>
<aop:advisor
pointcut="execution(* gov.usdoj.afms.umc.services.LookupService.removeUsrOrgLvlAsgnT(..))"
advice-ref="txAdvice"/>
<aop:advisor
pointcut="execution(* gov.usdoj.afms.umc.services.LookupService.addOrUpdateUsrOrgLvlAsgnT(..))"
advice-ref="txAdvice"/>
<aop:advisor
pointcut="execution(* gov.usdoj.afms.umc.services.LookupService.removeAndAddUsrOrgLvlAsgnT(..))"
advice-ref="txAdvice"/>
<aop:advisor
pointcut="execution(* gov.usdoj.afms.umc.services.St60Service.*(..))"
advice-ref="txAdvice"/>
</aop:config>
<bean id="serviceTarge" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager" />
<property name="target" ref="createUserService" />
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="UM04ServiceTarget" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager" />
<property name="target" ref="UM04Service" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="umcLookups" class="gov.usdoj.afms.umc.application.lookups.UMCLookups" init-method="init" scope="singleton">
<property name="lookupDao" ref="LookupDao"/>
</bean>
<bean id="userSearchServiceBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>gov.usdoj.afms.umc.services.UserSearchService</value>
</property>
<property name="target">
<ref bean="userSearchServiceImpl"/>
</property>
<property name="interceptorNames">
<list>
<value>theLogger</value>
</list>
</property>
</bean>
txManager覆盖就在那里,所以我们可以为CLIENT_INFO设置一些值,这允许我们用事务识别用户和模块,以便我们的审计触发器记录信息。
@Override
protected void doBegin(Object arg0, TransactionDefinition arg1)
{
super.doBegin(arg0, arg1);
if (!Db2ClientInfo.exists()) {
clearDBProperty();
} else {
setDBProperty(Db2ClientInfo.getClientUserId(), Db2ClientInfo.getClientApplicationId());
}
}
@Override
protected void doCommit(DefaultTransactionStatus status) {
super.doCommit(status);
clearDBProperty();
}
@Override
protected void doRollback(DefaultTransactionStatus status) {
super.doRollback(status);
clearDBProperty();
}
@SuppressWarnings("deprecation")
private void setDBProperty(String uId, String appName) {
Session session = getSessionFactory().getCurrentSession();
Properties props = new Properties();
props.setProperty(WSConnection.CLIENT_ID, uId);
props.setProperty(WSConnection.CLIENT_APPLICATION_NAME, appName);
try {
Connection nativeConn = new SimpleNativeJdbcExtractor().getNativeConnection(session.connection());
if (nativeConn instanceof WSConnection) {
WSConnection wconn = (WSConnection) nativeConn;
wconn.setClientInformation(props);
} else {
logger.error("Connection was NOT an instance of WSConnection so client ID and app could not be set");
}
} catch (Exception e) {
throw new RuntimeException("Cannot set DB parameters!", e);
}
}
/**
* Why clear this? Because we use a connection POOLER and we'd like to clear this info when it is checked into the pool.
*/
private void clearDBProperty() {
setDBProperty("", "");
}
答案 0 :(得分:2)
首先,HibernateTransactionManager.doBegin()
方法会抛出这段代码中的错误:
if (txObject.hasConnectionHolder() &&
!txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
throw new IllegalTransactionStateException(
"Pre-bound JDBC Connection found! HibernateTransactionManager does not support " +
"running within DataSourceTransactionManager if told to manage the DataSource itself. "+
"It is recommended to use a single HibernateTransactionManager for all transactions " +
"on a single DataSource, no matter whether Hibernate or JDBC access.");
}
此错误主要是由于:
引起的IllegalTransactionStateException
抛出以下异常消息(在HibernateTransactionManager.doBegin()中进行硬编码):预绑定的JDBC连接!如果告知要管理DataSource本身,HibernateTransactionManager不支持在DataSourceTransactionManager中运行。对于单个DataSource上的所有事务,建议使用单个HibernateTransactionManager,无论是Hibernate还是JDBC访问。
这是一个配置错误。检查整个配置以找出问题所在。
P.S .- 在任何情况下,异常消息都可能会产生误导,因为HibernateTransactionManager实际上可能在不是DataSourceTransactionManager的事务管理器中运行。
答案 1 :(得分:1)
我们认为我们解决了这个问题。我们,如问题陈述中所述,在一个EAR中有两个WAR。每个都有一个事务和一个sessionFactory,但它们指向相同的数据源。通过将它们分成指向不同的数据源,问题就消失了。 WAR是单独的应用程序,具有单独的psring configs等,所以我们假设它们就像是单独的应用程序,但显然它们可以以这种方式相互踩踏,因为它们存在于同一个EAR中。从长远来看,我们将它们拆分为单独的EAR,但是现在,将它们指向不同的数据源(即使两者指向具有相同用户的相同DB),也可以解决问题。