Spring JTA 分散式交易

來源:互聯網
上載者:User

本文涉及的代碼完整例子下載http://download.csdn.net/download/lanseba/2508881

有的時候我們的程式不止一個資料來源,並且需要在多資料來源中保證事務,那麼就需要用到分散式交易了..JTA -- java transaction api 。。哥研究了了一下。做了下總結,並給各位掉面人分享下。以便就分散式交易這個問題一勞永逸.

   環境 : mysql5.1   jdk 1.5+   spring 2.5 hibernate 3.x          Spring 對jta的支援真的很好。。。

      分散式交易必須使用的資料庫支援 並且提供 XA 串連驅動 如 mysql 的5.0+版本驅動中就有 com.mysql.jdbc.jdbc2.optional.MysqlXAConnection  等 這些對 XA 分布事務支援的串連 ,所以理所當然我們要使用XA事務就必須使用這種XA串連
 當然上面提到的 mysql5.1 是支援分布事務的 ,mysql驅動需要5.0+  哥推薦 mysql-connector-java-5.1.0
幾個驅動比較下來 哥覺得這個驅動最穩定 對XA的支援最好

 小二 上代碼  上配置!

      資料庫1 :jtatest1

 表:tusers
 
  列    類型 
  id    int  主鍵自增
  name   varchar(50) 非空
--------------------------------------------------------
 CREATE TABLE `tusers` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `name` varchar(50) NOT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

 
  資料庫1 :jtatest2

 表:product
 
  列     類型 
  id     int  主鍵自增
  price  float(11,0) 非空
--------------------------------------------------------

 CREATE TABLE `product` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `price` float(11,0) NOT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;

實體類,以及hibernate orm對應檔

package jtatest1;

public class Users implements java.io.Serializable {

 private Integer id;
 private String name;

 public Users() {
  
 }

 public Users(Integer id, String name) {
  this.id = id;
  this.name = name;
 }

 public Integer getId() {
  return this.id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getName() {
  return this.name;
 }

 public void setName(String name) {
  this.name = name;
 }

}

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="jtatest1.Users" table="tusers"  >
        <id name="id" type="java.lang.Integer">
            <column name="id" />
            <generator class="identity" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="name" length="100" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

 

 

package jtatest2;

 

public class Product implements java.io.Serializable {

 
 private Integer id;
 private Float price;

 

 public Product() {
 }

 public Product(Integer id, Float price) {
  this.id = id;
  this.price = price;
 }

 public Integer getId() {
  return this.id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public Float getPrice() {
  return this.price;
 }

 public void setPrice(Float price) {
  this.price = price;
 }

}

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="jtatest2.Product" table="product" >
        <id name="id" type="java.lang.Integer">
            <column name="id" />
            <generator class="identity" />
        </id>
        <property name="price" type="java.lang.Float">
            <column name="price" precision="53" scale="0" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

 

下面是DAO 和 BIZ

package jtatest.daoimpl;

import jtatest.dao.ProductDao;
import jtatest2.Product;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class ProductDaoimpl extends HibernateDaoSupport implements ProductDao {

 public void save(Product p){
  this.getHibernateTemplate().save(p);
 }
}

 

package jtatest.daoimpl;

import jtatest.dao.UserDao;
import jtatest1.Users;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class UserDaoimpl extends HibernateDaoSupport implements UserDao {
 
 

 public void save(Users u){
  this.getHibernateTemplate().save(u);
 }
 
}

package jtatest.dao;

import jtatest2.Product;

public interface ProductDao {

 public abstract void save(Product p);

}

package jtatest.dao;

import jtatest1.Users;

public interface UserDao {

 public abstract void save(Users u);

}

package jtatest.bizimpl;

import jtatest.biz.Biz;
import jtatest.dao.ProductDao;
import jtatest.dao.UserDao;
import jtatest1.Users;
import jtatest2.Product;

public class Bizimpl implements Biz {

 
 private ProductDao productDao = null;
 
 private UserDao userDao = null;
 

 public void save(Product p, Users u) {
  productDao.save(p);
  userDao.save(u);
 }

 public void setProductDao(ProductDao productDao) {
  this.productDao = productDao;
 }

 public void setUserDao(UserDao userDao) {
  this.userDao = userDao;
 }

}

 

package jtatest.biz;

import jtatest1.Users;
import jtatest2.Product;

public interface Biz {
 public void save(Product p, Users u);
}

2個Hibernate 的配置

hibernate-jtatest1.cfg.xml

<hibernate-configuration>

<session-factory>
 <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
 <property name="show_sql">true</property>
 <mapping resource="jtatest1/Users.hbm.xml" />
</session-factory>

</hibernate-configuration>

-------------------------------------------

hibernate-jtatest2.cfg.xml

<hibernate-configuration>

<session-factory>
 <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
 <property name="show_sql">true</property>
 <mapping resource="jtatest2/Product.hbm.xml" />
</session-factory>
</hibernate-configuration>

好了 基本垃圾代碼就是上面了的了 剩下的就是使用spring管理JTA了  可以使用 JOTM 或者是 ATOMIKOS 等 但是 貌似JOTM需要 JNDI 的支援 脫離不了Web伺服器,
而 atomikos 則不需要JNDI的支援 所以哥推薦使用 atomikos 它也是開源產品, http://www.atomikos.com/downloads/transactions-essentials/3.5.5/AtomikosTransactionsEssentials-3.5.5.zip
使用spring 管理jta事務  你不需要寫一句事務代碼 真是NB啊。。。
各位掉面人可能主要道上面的hibernate配置中沒有使用者名稱密碼,那是因為我們需要在spring中注入一個XADataSource到hibernate中去 好讓hibernate擷取的串連是XAConnection
這裡使用atomikos的 XADataSource 配置 :

  <bean id="ds1" class="com.atomikos.jdbc.SimpleDataSourceBean"
  init-method="init" destroy-method="close">
  <property name="uniqueResourceName">
   <value>mysql/ds1</value>   這裡注意 多個datasource中不能重名
  </property>
  <property name="xaDataSourceClassName">
   <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
  </property>
  <property name="xaDataSourceProperties">
   <value>URL=jdbc:mysql://localhost:3306/jtatest1?user=root;password=admin</value>
  </property>
  <property name="exclusiveConnectionMode">
   <value>true</value>
  </property>
  <property name="connectionPoolSize">
   <value>3</value>
  </property>
  <property name="validatingQuery">
   <value>SELECT 1</value>
  </property>
 </bean>
 
 <bean id="ds2"
  class="com.atomikos.jdbc.SimpleDataSourceBean" init-method="init"
  destroy-method="close">
  <property name="uniqueResourceName">
   <value>mysql/ds2</value>
  </property>
  <property name="xaDataSourceClassName">
   <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
  </property>
  <property name="xaDataSourceProperties">
   <value>URL=jdbc:mysql://localhost:3306/jtatest2?user=root;password=admin</value>
  </property>
  <property name="exclusiveConnectionMode">
   <value>true</value>
  </property>
  <property name="connectionPoolSize">
   <value>3</value>
  </property>
  <property name="validatingQuery">
   <value>SELECT 1</value>
  </property>
 </bean>

這樣就可以給hibernate 注入 datasource了

 <bean id="sessionFactory1"
  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  <property name="configLocation"
   value="classpath:hibernate-jtatest1.cfg.xml" />
  <property name="dataSource" ref="ds1"></property>
 </bean>
 <bean id="sessionFactory2"
  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  <property name="configLocation"
   value="classpath:hibernate-jtatest2.cfg.xml" />
  <property name="dataSource" ref="ds2"></property>
  
 </bean>
下面管理 BIZ 和DAO

 <bean id="biz" class="jtatest.bizimpl.Bizimpl">
  <property name="productDao" ref="productDao" />
  <property name="userDao" ref="userDao" />
 </bean>

 <bean id="userDao" class="jtatest.daoimpl.UserDaoimpl">
  <property name="sessionFactory" ref="sessionFactory1" />
 </bean>

 <bean id="productDao" class="jtatest.daoimpl.ProductDaoimpl">
  <property name="sessionFactory" ref="sessionFactory2" />
 </bean>

OK  萬事俱備了  就等陪事務了 基本和spring 管理的普通事務過程差不多
首先需要一個交易管理員

<bean id="atomikosTransactionManager"
  class="com.atomikos.icatch.jta.UserTransactionManager"
  init-method="init" destroy-method="close">
  <property name="forceShutdown">
   <value>true</value>
  </property>
 </bean>

com.atomikos.icatch.jta.UserTransactionManager 實現了 javax.transaction.TransactionManager 介面 這個介面不能和  tx:advice 的transaction-manager相容
,so 還需封裝下
 
 <bean id="txManager"
  class="org.springframework.transaction.jta.JtaTransactionManager">
  <property name="userTransaction" ref="atomikosUserTransaction" />
  <property name="transactionManager" ref="atomikosTransactionManager"></property>
 </bean>

 這個是atomikos事務的實現
 <bean id="atomikosUserTransaction"
  class="com.atomikos.icatch.jta.UserTransactionImp">
  <property name="transactionTimeout">
   <value>6000</value>
  </property>
 </bean>

這樣  配的txManager就穿上了Spring交易管理員的外套了

下面就是  織入通知了

 <tx:advice id="advice" transaction-manager="txManager">
  <tx:attributes>
   <tx:method name="save*" propagation="REQUIRED" />
   <tx:method name="delete*" propagation="REQUIRED" />
   <tx:method name="*" read-only="false" />
  </tx:attributes>
 </tx:advice>

 <aop:config>
  <aop:pointcut id="point"
   expression=" execution(* jtatest.bizimpl.*.*(..))" />
  <aop:advisor advice-ref="advice" pointcut-ref="point" />
 </aop:config>

大功告成  可以測試了

  public static void main(String[] args) {
  ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
   BeanFactory bf = context;
  
   Biz biz = (Biz) bf.getBean("biz");
  
   Product p = new Product();
   p.setPrice(10f);
  
   Users u = new Users();
   u.setName(null); //非空欄位 插入一個空試試 ,再給個值試試  
   biz.save(p, u);
  
  
 
 }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.