0

我们得到了错误

org.springframework.transaction.IllegalTransactionStateException:找到预绑定的 JDBC 连接!如果被告知要管理 DataSource 本身,HibernateTransactionManager 不支持在 DataSourceTransactionManager 中运行。建议对单个 DataSource 上的所有事务使用单个 HibernateTransactionManager,无论是 Hibernate 还是 JDBC 访问。

它发生的地方是我们覆盖事务管理器的地方,这样我们就可以对 doBegin、commit 和 rollback 方法做出反应。但是,错误发生在我们调用 super.doBegin() 的 doBegin 中,并且在我们的任何代码实际运行之前。就我们希望发生的情况而言,该错误也是高度间歇性和不合作的。

我在网上看到很多人建议这通常意味着您定义了两个事务管理器。我最初拒绝了这个申请,因为我们没有。我仔细检查了一遍。但是,没那么快,也许我会。虽然我们的战争只有一个 tx 管理器,但发生这种情况的应用程序……发生这种情况的唯一应用程序……是同一个 EAR 中的两场战争。每个都有它自己定义的 spring 上下文和它自己的 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("", "");
}
4

2 回答 2

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.");
}

此错误主要是由于:

  • 不同的 SessionFactory实例(A 和 B)配置两个HibernateTransactionManager实例(A 和 B)——可能使用相同的底层 DataSource
  • 然后A 的事务方法调用B事务方法,抛出以下异常消息(在 HibernateTransactionManager.doBegin() 中硬编码):IllegalTransactionStateException

找到预绑定的 JDBC 连接!如果被告知要管理 DataSource 本身,HibernateTransactionManager 不支持在 DataSourceTransactionManager 中运行。建议对单个 DataSource 上的所有事务使用单个 HibernateTransactionManager,无论是 Hibernate 还是 JDBC 访问。

这是一个配置错误。检查您的整个配置以找出问题所在。

PS-在任何情况下,异常消息都可能具有误导性,因为 HibernateTransactionManager 实际上可能在不是 DataSourceTransactionManager 的事务管理器中运行。

于 2013-09-26T19:16:50.260 回答
1

我们认为我们解决了这个问题。如问题陈述中所述,我们在一个 EAR 中有两个 WAR。每个都有一个事务和一个 sessionFactory,但它们指向同一个数据源。通过将它们拆分为指向不同的数据源,问题就消失了。WAR 是具有单独 psring 配置等的单独应用程序,因此我们假设它们就像单独的应用程序,但显然它们可以通过这种方式相互影响,因为它们位于同一个 EAR 中。从长远来看,我们会将它们拆分为单独的 EAR,但现在,将它们指向不同的数据源(即使两个指向具有相同用户的同一个数据库等)可以解决问题。

于 2013-09-30T17:28:44.337 回答