使用JOTM進行Tomcat的JTA調用

前段時間碰到一個需要訪問多個數據庫的例子,由於項目上是採用tomcat作爲項目開發和佈署,所以就沒有考慮採用特定廠商的JTA實現,而是通過一個開源的JTA實現來完成tomcat和多個數據庫之間的直接交互。

    多數據庫訪問最直接的問題就是在一個service中,存在着多個數據庫dao對象,當前面的dao對象操作完成之後,如果後面的某一個dao訪問出錯,那麼這個service應該如何進行回滾呢。一般來說,回滾應該是整個service一起回滾,所以就需要對這個service中的所有dao所涉及的sessionFactory進行處理。而對於hibernate+spring來說,spring是使用hibernate的sessionFactory來進行事務的控制和回滾的,而hibernate又是將由自己的一個transactionFactory引用相關的transaction來進行事務的提交和回滾。所以,如果要用到多個數據庫,就需要一個支持多個數據庫的transaction。JOTM就提供了一個開源的多數據庫Transaction應用,它採用了支持XADatasource的Xpool來進行數據源管理。

    1,首先需要在項目中引入以下包:

Java代碼  
  1. <!--這個爲jotm的核心包 -->  
  2. <dependency>  
  3.     <groupId>org.ow2.jotm</groupId>  
  4.     <artifactId>jotm-core</artifactId>  
  5.     <version>2.2.1</version>  
  6. </dependency>  
  7. <!-- 這個爲xappol即XaDatasource的一個開源實現 -->  
  8. <dependency>  
  9.     <groupId>com.experlog</groupId>  
  10.     <artifactId>xapool</artifactId>  
  11.     <version>1.5.0</version>  
  12. </dependency>  
  13. <!-- jotm的數據操作類包 -->  
  14. <dependency>  
  15.     <groupId>org.ow2.jotm</groupId>  
  16.     <artifactId>jotm-datasource</artifactId>  
  17.     <version>2.2.1</version>  
  18. </dependency>  
  19. <!-- cmi配置包,jotm初始化時需要相應的包 -->  
  20. <dependency>  
  21.     <groupId>org.ow2.cmi</groupId>  
  22.     <artifactId>cmi-all</artifactId>  
  23.     <version>2.0-RC7</version>  
  24. </dependency>  
  25. <!-- j2ee的api,tomcat中沒有中 -->  
  26. <dependency>  
  27.     <groupId>geronimo-spec</groupId>  
  28.     <artifactId>geronimo-spec-j2ee-connector</artifactId>  
  29.     <version>1.5-rc4</version>  
  30. </dependency>  

  2,在配置文件的根目錄增加一個carol.properties文件(此文件是一個對命名空間以及jndi的配置支持)

Java代碼  收藏代碼
  1. carol.protocols=jrmp  
  2. carol.jvm.rmi.local.call=true  
  3. carol.start.jndi=false  
  4. carol.start.ns=false  
  5. carol.jndi.java.naming.factory.url.pkgs=org.apache.naming  

 

3,在項目中配置數據源連接,這裏就不能在spring或者hibernate的配置文件中配置數據源了(當然,如果配置成xadatabase可能會正確,沒嘗試過)。在web應用中,在webapp下新建立META-INF文件夾,並新建立context.xml文件。(有些文件說直接在tomcat的service.xml中創建,其實在每個項目中建立更加獨立)tomcat在加載項目時會自動加載此文件。

Java代碼  收藏代碼
  1. <?xml version='1.0' encoding='utf-8'?>  
  2. <Context reloadable="false">  
  3.     <Resource name="jdbc/gtip"  
  4.               auth="Container"  
  5.               type="javax.sql.DataSource"  
  6.               factory="org.objectweb.jotm.datasource.DataSourceFactory"  
  7.               driverClassName="com.mysql.jdbc.Driver"  
  8.               username="root" password=""  
  9.               url="jdbc:mysql://localhost/gtip"/>  
  10.     <Resource name="jdbc/gtipext"  
  11.               auth="Container"  
  12.               type="javax.sql.DataSource"  
  13.               factory="org.objectweb.jotm.datasource.DataSourceFactory"  
  14.               driverClassName="com.mysql.jdbc.Driver"  
  15.               username="root" password=""  
  16.               url="jdbc:mysql://localhost/gtipext"/>  
  17.   
  18.     <Resource name="UserTransaction"  
  19.               auth="Container"  
  20.               type="javax.transaction.UserTransaction"/>  
  21.   
  22.     <Transaction factory="org.objectweb.jotm.UserTransactionFactory"  
  23.                  jotm.timeout="60"/>  

 

這裏建立了兩個數據源,一個爲gtip,一個爲gtipext,且聲明瞭一個默認的事務UserTransaction,同時聲明瞭一個事務提供工廠,表示由jotm提供了一個事務實現。

4,在項目中引用這兩個數據源,即在web.xml中引用數據源。

Java代碼  收藏代碼
  1. <resource-env-ref>  
  2.     <description>gtip</description>  
  3.     <resource-env-ref-name>jdbc/gtip</resource-env-ref-name>  
  4.     <resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type>  
  5. </resource-env-ref>  
  6. <resource-env-ref>  
  7.     <description>gtip</description>  
  8.     <resource-env-ref-name>jdbc/gtipext</resource-env-ref-name>  
  9.     <resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type>  
  10. </resource-env-ref>  

 

這裏即表示需要引用兩個數據源定義

5,在hibernate.cfg.xml中配置數據源,表示引用此數據源

Java代碼  收藏代碼
  1. <property name="connection.datasource">java:comp/env/jdbc/gtipext</property>  

 

這裏就會引用gtipext的數據源,表示hibernate將通過此來尋找相應的datasource實現

6,在spring.xml中配置事務,並通知hibernate引用相關jtaTransactionFactory

Java代碼  收藏代碼
  1. <bean id="jotm" class="com.greejoy.develop.bean.JotmFactoryBean"/>  

 此是一個jotmBean定義,此bean在Spring3.x版本上已經沒有了,所以可以從spring2.5.6版本上直接將源碼copy過來即可。這裏就是一個工廠bean,去最終創建出一個jotm的current對象(或者不是創建,而是直接通過靜態引用Current.getCurrent()直接獲取)。在這裏,就需要一個手段來獲取到jotm對象。

Java代碼  收藏代碼
  1. <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">  
  2.     <property name="transactionManager" ref="jotm"/>  
  3. </bean>  

 

事務管理器聲明,表示定義了一個jta的事務管理器(其實它最沒有實現transactionManager接口),但是最終的事務管理將由具體的transactionManager去實現,即將實現transactionManager的工作委派給容器或者具體的實現去做。

Java代碼  收藏代碼
  1. <bean id="sessionFactory"  
  2.  class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">  
  3.     <property name="configLocations" value="classpath*:conf/**/hibernate.cfg.xml"/>  
  4.     <property name="jtaTransactionManager" ref="jotm"/>  
  5. </bean>  

Hibernate的sessionFactory定義聲明,其中需要一個jtaTransactionManager的屬性定義,當hibernate解析此屬性時,將會指定hibernate的transactionFactory實現爲JTATransactionFactory(默認它會指定爲JDBCTransactionFactory)。

 

至此,相應的配置工作即結束,在項目中可以使用spring跟以前一個的定義事務控制aop,並交由相關的transactionManager去進行控制。

 

ps:在spring的AnnotationSessionFactoryBean來說,在配置了jtaTransactionManager之後,spring會往hibernate中配置一個屬性hibernate.transaction.manager_lookup_class,並引用hibernate尋找到相應的transactionManager。但是hibernate在3.5.3版本實現中,並沒有使用lookupClass來尋找transactionManger,而是使用其去尋找userTransactionName,再自己根據userTransactionName通過initContext來取得transactionManager。在srping3.x的實現中,lookupClass(即LocalTransactionManagerLookup)的getUserTransactionName會返回null(雖然其getTransactionManager會返回相應的transactionManager)。hibernate沒有使用這個方法,而是使用了getTransactionUsername方法。兩者顯示沒有很好的對接,或者是其中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章