spring項目加入jta分佈式事務的實現方式: Atomikos

1、概述:java

本文主要講述如何基於Atomikos 和spring在項目中實現分佈式事務管理mysql

2、應用場景:spring

若是項目中的數據源來自多個數據庫,同時又須要在多數據源中保證事務,此時就須要用到分佈式事務處理了。sql

3、實驗模擬需求:數據庫

好比有兩個對象:用戶信息、用戶存款,用戶信息存在數據庫A、存款信息存在數據庫B,若客戶甲向乙轉帳,須要在數據庫B中對甲、乙的存款信息修改,同時在數據庫A中把甲、乙的備註信息最新爲最近一次的操做時間。分佈式

4、實例測試環境:測試

spring、hibernate3.2atom

mysql5.1.51(須要版本5.0+)spa

AtomikosTransactionsEssentials-3.7.0 (詳細可參加它的官網:http://www.atomikos.com  )hibernate

說明:

1. 測試的數據庫須要支持分佈式事務,同時JDBC要支持XA鏈接驅動。本次測試用的mysql5.1是支持事務的,JDBC驅動版本:mysql-connector-java-5.1.7-bin.jar,包含對 XA鏈接的支持:com.mysql.jdbc.jdbc2.optional.MysqlXAConnection。

5、代碼及配置介紹:

源代碼下載:分佈式事務實例演示源代碼michael_jta_code.zip

1.代碼的目錄結構圖以下:

轉帳代碼片斷:

/**
     * 轉帳測試
     * @param srcId
     * @param destId
     * @param money
     * @return boolean
     */
    public boolean doTestTransfer(String srcId, String destId, float money) {

        BankAccount srcAccount = bankAccountDao.getByUserName(srcId);
        BankAccount destAccount = bankAccountDao.getByUserName(destId);
        if (srcAccount.getDeposit() < money) {
            System.out.println("warn :" + srcAccount.getUserName()
                    + " has not enough money to transfer");
            return false;
        }
        srcAccount.setDeposit(srcAccount.getDeposit() - money);
        destAccount.setDeposit(destAccount.getDeposit() + money);
        bankAccountDao.update(srcAccount);
        bankAccountDao.update(destAccount);

        Date curTime = new Date();
        UserInfo srcUser = userInfoDao.getById(srcId);
        UserInfo destUser = userInfoDao.getById(destId);

        destUser.setRemark1(curTime + "");
        destUser.setRemark2(curTime + "");
        userInfoDao.update(destUser);
        srcUser.setRemark1(curTime + "");
        if (srcAccount.getDeposit() < 18000) {
            throw new RuntimeException("michael test exception for JTA  ");
        }
        srcUser.setRemark2(curTime + "");
        userInfoDao.update(srcUser);
        System.out.println("success done:" + srcAccount.getUserName()
                + " transfer ¥" + money + " to " + destAccount.getUserName());

        return true;
    }


jta.jdbc.properties:

jdbc.SDS.class=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
jdbc.SDS.properties=URL=jdbc:mysql://localhost:3306/Test1;user=root;password=root

jdbc.SDS2.class=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
jdbc.SDS2.properties=URL=jdbc:mysql://localhost:3306/Test2;user=root;password=root

jta.properties

com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
com.atomikos.icatch.console_file_name = tm.out
com.atomikos.icatch.log_base_name = tmlog
com.atomikos.icatch.tm_unique_name = com.atomikos.spring.jdbc.tm
com.atomikos.icatch.console_log_level = INFO


6、測試驗證

1. 初始化數據:

由於mysql數據庫表的類型有事務和非事務之分,建表時必定要注意確保表的類型是事務控制的:InnoDB

如下兩張表請分部在兩個不一樣的數據庫

CREATE TABLE tb_user_info (
	user_name varchar(20),
	real_name varchar(10),
	remark1 varchar(50),
	remark2 varchar(50)
	) ENGINE = InnoDB;
 
INSERT INTO tb_user_info (user_name,real_name,remark1,remark2) VALUES ('husband','husband','','');
INSERT INTO tb_user_info (user_name,real_name,remark1,remark2) VALUES ('wife','wife','','');
CREATE TABLE tb_account (
 id int AUTO_INCREMENT,
 user_name varchar(20),
 deposit float(10,2),
 PRIMARY KEY(id)
 ) ENGINE = InnoDB;
 
INSERT INTO tb_account (user_name,deposit) VALUES ('husband',20000.00);
INSERT INTO tb_account (user_name,deposit) VALUES ('wife',10000.00);
相關文章
相關標籤/搜索