2009-12-29 58 views
3

我最初使用xapool創建了spring,但事實證明這是一個死了的項目,似乎有很多問題。spring事務性池。我使用哪一個?

我切換到c3p0,但現在我知道@Transactional註釋實際上不會在與c3p0一起使用時創建事務。如果我下面會甚至通過異常將該行插入符是在方法內部拋出:

@Service 
public class FooTst 
{ 
    @PersistenceContext(unitName="accessControlDb") private EntityManager em; 

    @Transactional 
    public void insertFoo() { 
     em.createNativeQuery("INSERT INTO Foo (id) VALUES (:id)") 
      .setParameter("id", System.currentTimeMillis() % Integer.MAX_VALUE) 
      .executeUpdate(); 

     throw new RuntimeException("Foo"); 
    } 

} 

這很奇怪,因爲如果我註釋掉@Transactional註釋它實際上將失敗,並抱怨有事務設置爲僅回滾:

java.lang.IllegalStateException: Cannot get Transaction for setRollbackOnly 
    at org.objectweb.jotm.Current.setRollbackOnly(Current.java:568) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.markAsRollback(AbstractEntityManagerImpl.java:421) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:576) 
    at org.hibernate.ejb.QueryImpl.executeUpdate(QueryImpl.java:48) 
    at com.ipass.rbac.svc.FooTst.insertFoo(FooTst.java:21) 
    at com.ipass.rbac.svc.SingleTst.testHasPriv(SingleTst.java:78) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.springframework.test.context.junit4.SpringTestMethod.invoke(SpringTestMethod.java:160) 
    at org.springframework.test.context.junit4.SpringMethodRoadie.runTestMethod(SpringMethodRoadie.java:233) 
    at org.springframework.test.context.junit4.SpringMethodRoadie$RunBeforesThenTestThenAfters.run(SpringMethodRoadie.java:333) 
    at org.springframework.test.context.junit4.SpringMethodRoadie.runWithRepetitions(SpringMethodRoadie.java:217) 
    at org.springframework.test.context.junit4.SpringMethodRoadie.runTest(SpringMethodRoadie.java:197) 
    at org.springframework.test.context.junit4.SpringMethodRoadie.run(SpringMethodRoadie.java:143) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:160) 
    at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51) 
    at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44) 
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27) 
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37) 
    at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:97) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) 

因此,顯然它注意到@Transactional註釋。但是,它並沒有在方法開始時將autocommit設置爲off。

這是我如何在applicationContext.xml中設置事務性的東西。它是否正確?如果沒有,這應該是什麼?

<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/> 
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"> 
    <property name="transactionManager" ref="jotm"/> 
    <property name="userTransaction" ref="jotm"/> 
    <property name="allowCustomIsolationLevels" value="true"/> 
</bean> 
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="false"/> 

一堆搜索後,我發現所謂Bitronix一個連接池,但他們的春天設置頁面介紹了有關JMS它甚至沒有任何意義的東西。 JMS與建立連接池有什麼關係?

所以我卡住了。我實際上應該做什麼?我不明白爲什麼連接池需要支持事務。所有連接都支持打開和關閉自動提交功能,所以我不知道問題出在哪裏。

回答

2

它花了很多搜索和實驗,但我終於得到了工作。這裏是我的結果:

  • enhydra xapool是一個可怕的連接池。我不會列舉它造成的問題,因爲這並不重要。該池的最新版本自2006年12月以來尚未更新。這是一個死了的項目。
  • 我把c3p0放到了我的應用程序上下文中,讓它工作得相當簡單。但是,由於某種原因,即使在單一方法中,它似乎也不支持回滾。如果我將一個方法標記爲@Transactional,然後對錶進行插入,然後拋出一個RuntimeException(一個肯定沒有在方法的throws列表中聲明的方法,因爲方法中沒有throws列表),它仍然會保持插入那張桌子。它不會回滾。
  • 我打算嘗試Apache DBCP,但是我的搜索引起了很多關於它的抱怨,所以我沒有打擾。
  • 我嘗試過Bitronix,並且在Tomcat下正常工作時遇到了很多麻煩,但是一旦我找到了它的神奇配置,它就可以很好地工作。接下來就是你需要做的所有事情來正確設置它。
  • 我用Atomkos連接池簡單地介紹了一下。它看起來應該是好的,但是我讓Bitronix首先工作,所以我沒有嘗試使用它。

下面以獨立的單元測試和Tomcat下作品的配置。這是我的主要問題。我發現的大部分關於如何使用Bitronix設置Spring的例子都假設我正在使用JBoss或其他完整的容器。

配置的第一位是,設定所述Bitronix事務管理器的部分。

<!-- Bitronix transaction manager --> 
<bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices"> 
    <property name="disableJmx" value="true" /> 
</bean> 
<bean id="btmManager" factory-method="getTransactionManager" class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig" destroy-method="shutdown"/> 
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> 
    <property name="transactionManager" ref="btmManager" /> 
    <property name="userTransaction" ref="btmManager" /> 
    <property name="allowCustomIsolationLevels" value="true" /> 
</bean> 
<tx:annotation-driven transaction-manager="transactionManager" /> 

該代碼和我找到的例子之間的主要區別是「disableJmx」屬性。如果您不使用JMX但將其保持爲啓用狀態,則會在運行時引發異常。

配置的下一個比特是連接池數據源。請注意,連接池類名不是正常的oracle類「oracle.jdbc.driver.OracleDriver」。這是一個XA數據源。我不知道其他數據庫中的等效類是什麼。

<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init" destroy-method="close"> 
    <property name="uniqueName" value="dataSource-BTM" /> 
    <property name="minPoolSize" value="1" /> 
    <property name="maxPoolSize" value="4" /> 
    <property name="testQuery" value="SELECT 1 FROM dual" /> 
    <property name="driverProperties"><props> 
     <prop key="URL">${jdbc.url}</prop> 
     <prop key="user">${jdbc.username}</prop> 
     <prop key="password">${jdbc.password}</prop> 
    </props></property> 
    <property name="className" value="oracle.jdbc.xa.client.OracleXADataSource" /> 
    <property name="allowLocalTransactions" value="true" /> 
</bean> 

還要注意,uniqueName需要與您配置的任何其他數據源不同。

課程的testQuery需要具體到你所使用的數據庫。驅動程序屬性特定於我正在使用的數據庫類。由於某些愚蠢的原因,OracleXADataSource對於OracleDriver具有相同值的不同setter名稱。

的allowLocalTransactions必須設置爲true我。我發現建議不要將其設置爲真實在線。但是,這似乎是不可能的。如果設置爲false,它將不起作用。我對這些事情知之甚少,不知道這是爲什麼。

最後,我們需要配置實體管理器工廠。

<util:map id="jpa_property_map"> 
    <entry key="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.BTMTransactionManagerLookup"/> 
    <entry key="hibernate.current_session_context_class" value="jta"/> 
</util:map> 

<bean id="dataSource-emf" name="accessControlDb" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="dataSource"/> 
    <property name="persistenceXmlLocation" value="classpath*:META-INF/foo-persistence.xml" /> 
    <property name="jpaVendorAdapter"> 
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
      <property name="showSql" value="true"/> 
      <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect"/> 
     </bean> 
    </property> 
    <property name="jpaPropertyMap" ref="jpa_property_map"/> 
    <property name="jpaDialect"><bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/></property> 
</bean> 

請注意dataSource屬性是指我聲明的dataSource的id。 persistenceXmlLocation引用存在於類路徑中的持久xml文件。 classpath *:表示它可能在任何jar中。如果沒有*,由於某種原因它不會出現在jar中。

我發現util:map是一種方便的方法,可以將jpaPropertyMap值放在一個地方,這樣我就不需要在一個應用程序上下文中使用多個實體管理器工廠時重複它們。

注意,UTIL:上述地圖將無法正常工作,除非您在外部豆元素正確的設置。下面是我使用的XML文件的標題:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:p="http://www.springframework.org/schema/p" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-2.5.xsd 
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> 

最後,爲了(支持兩個階段提交或顯然任何CPOOL)與甲骨文工作,你需要運行下面的贈款用戶SYS的Bitronix 。 (見http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/rtrb_dsaccess2.htmlhttp://docs.codehaus.org/display/BTM/FAQhttp://docs.codehaus.org/display/BTM/JdbcXaSupportEvaluation#JdbcXaSupportEvaluation-Oracle

grant select on pending_trans$ to <someUsername>; 
grant select on dba_2pc_pending to <someUsername>; 
grant select on dba_pending_transactions to <someUsername>; 
grant execute on dbms_system to <someUsername>; 

這些補助需要一個連接池設立無論你是否真正做的任何事情任何修改任何用戶運行。它顯然在建立連接時查找這些表。

了一些小問題:

  • 您不能查詢它們而春季@事務塊裏面的Oracle遠程同義詞,而使用Bitronix表(你會得到一個ORA-24777)。使用物化視圖或單獨的EntityManager,直接指向另一個數據庫。
  • 由於某些原因,applicationContext.xml中的btmConfig在設置配置值時遇到了問題。相反,請創建一個bitronix-default-config.properties文件。您可以使用的配置值可在http://docs.codehaus.org/display/BTM/Configuration13找到。該文件的一些其他配置信息在http://docs.codehaus.org/display/BTM/JdbcConfiguration13,但我沒有使用它。
  • Bitronix使用一些本地文件來存儲事務性內容。我不知道爲什麼,但我知道如果你有多個帶有本地連接池的webapps,你將會遇到問題,因爲它們都會嘗試訪問相同的文件。要解決此問題,請爲每個應用程序的bitronix-default-config.properties中的bitronix.tm.journal.disk.logPart1Filename和bitronix.tm.journal.disk.logPart2Filename指定不同的值。
  • Bitronix javadocs在http://www.bitronix.be/uploads/api/index.html

就是這樣。開始工作非常繁瑣,但現在正在工作,我很高興。我希望所有這些都能幫助那些正在經歷同樣麻煩的人來完成這一切。

0

當我做連接池時,我傾向於使用我部署的應用服務器提供的連接池。這只是Spring的JNDI名稱。

由於我在測試時不想擔心應用程序服務器,因此我在進行單元測試時使用了DriverManagerDataSource及其關聯的事務管理器。測試時我並不擔心集合或性能。我確實希望測試能夠有效地運行,但在這種情況下,並不是一個交易斷路器。

+0

我使用tomcat,所以它不提供任何東西。 – HappyEngineer

+0

確實如此 - 您爲什麼不要求它使用Jakarta DBCP提供連接池? http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html – duffymo

+0

無論如何,我需要將應用程序上下文設置爲獨立運行或在tomcat下運行。 對於我的生活,我無法弄清楚如何讓事情剛剛運行,以便在@Transactional方法中拋出的異常導致在同一方法中執行的插入回滾。這非常令人沮喪。我不需要2階段提交或類似的東西。只需一個簡單的交易即可。除此之外的任何事情都是獎金。 – HappyEngineer

相關問題