2013-09-26 123 views
0

我們所得到的是錯誤多戰爭耳

org.springframework.transaction.IllegalTransactionStateException發現預先綁定JDBC連接:預先綁定的JDBC Connection找到了!如果被告知管理數據源本身,HibernateTransactionManager不支持在DataSourceTransactionManager中運行。無論Hibernate還是JDBC訪問,都建議對單個DataSource上的所有事務使用單個HibernateTransactionManager。

它發生的地方是我們重寫事務管理器的地方,以便我們可以對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("", ""); 
} 
+0

你不應該重寫事務管理器,你可以手動啓動和停止事務。 – Jaiwo99

+0

我們可以看到bean的定義,以及如何超越這個方法。你在你的應用程序中進行任何直接的JDBC調用..? – user2339071

+0

@ Jaiwo99 - 手動啓動和停止?我們所做的只是試圖獲取一個掛鉤來通知tx何時啓動和停止,以便代碼可以自動響應並設置審計信息。我們使用註釋和aop事務觸發,所以我們使用它作爲單個代碼點來執行此標準工作。如果您有更好的建議,請解釋,因爲我不瞭解您關於手動的評論。 – user1187719

回答

1

我們認爲我們解決了這個問題。正如問題陳述中所述,我們在一個EAR中有兩個WAR。每個都有一個事務和一個sessionFactory,但它們指向相同的數據源。通過分裂他們指向不同的數據源,問題就消失了。 WARs是獨立的psring configs等人的獨立應用程序,所以我們假定他們就像是單獨的應用程序,但顯然他們可以這樣彼此接觸,因爲他們生活在同一個EAR中。從長遠來看,我們將把它們分解成單獨的EAR,但現在,將它們指向不同的數據源(即使兩個指向具有相同用戶的相同DB)解決了這個問題。

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

此錯誤主要是起因於:

  • 配置的實例HibernateTransactionManager(A和B)不同SessionFactory個實例(A和B) - 潛在地使用相同的底層的DataSource
  • 然後,對於甲一個事務方法調用一個事務方法,一個IllegalTransactionStateException拋出具有以下例外消息( 在HibernateTransactionManager.doBegin())硬編碼:

預先綁定的JDBC Connection找到了!如果被告知管理數據源本身,HibernateTransactionManager不支持在DataSourceTransactionManager中運行。無論Hibernate還是JDBC訪問,都建議對單個DataSource上的所有事務使用單個HibernateTransactionManager。

這是一個配置錯誤。檢查你的整個配置,找出問題所在。

P.S.-在任何情況下,由於HibernateTransactionManager實際上可能在不是DataSourceTransactionManager的事務管理器中運行,所以異常消息可能會引起誤解。

+0

鏈接到答覆/ copypaste的來源本來不錯。 https://jira.spring.io/browse/SPR-9496 –