1 环境

1.1 软件环境

 spring-framework-2.5.6.SEC01-with-dependencies.zip
 ibatis-2.3.4
 ow2-jotm-dist-2.1.4-bin.tar.gz
 MySQL-5.1
 JDK1.5
 
1.2 创建数据库环境
注意mysql里数据库引擎为InnoDB,只有这样才能支持事务。
 CREATE DATABASE IF NOT EXISTS testdb_a    DEFAULT CHARACTER SET utf8; 

 USE testdb_a; 

 DROP TABLE IF EXISTS tab_a; 

 CREATE TABLE tab_a (
id bigint(20) NOT NULL,
name varchar(60) DEFAULT NULL,
address varchar(120) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE DATABASE IF NOT EXISTS testdb_b DEFAULT CHARACTER SET utf8; USE testdb_b; DROP TABLE IF EXISTS tab_b; CREATE TABLE tab_b (
id bigint(20) NOT NULL,
name varchar(60) DEFAULT NULL,
address varchar(120) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

建立项目testJOTM

2.1 建立项目后,准备依赖的类库,结构如下

2.2 主要代码

 /**
* 测试JOTM的Service
*
* @author leizhimin 2009-6-25 12:53:55
*/
public interface StuJotmService {
/**
* 同时保存TabA、TabB
*
* @param a
* TabA对象
* @param b
* TabB对象
*/
void saveAB(TabA a, TabB b); /**
* 同时更新TabA、TabB
*
* @param a
* TabA对象
* @param b
* TabB对象
*/
void updateAB(TabA a, TabB b); /**
* 删除指定id的TabA、TabB记录
*
* @param id
* 指定id
*/
void deleteABif(Long id);
}

StuJotmService

 public class StuJotmServiceImpl implements StuJotmService {
private TabADAO tabADAO;
private TabBDAO tabBDAO; /**
* 同时保存TabA、TabB
*
* @param a
* TabA对象
* @param b
* TabB对象
*/
// @Transactional(readOnly=false)
public void saveAB(TabA a, TabB b) {
tabADAO.saveTabA(a);
tabBDAO.saveTabB(b);
} /**
* 同时更新TabA、TabB
*
* @param a
* TabA对象
* @param b
* TabB对象
*/
// @Transactional(readOnly=false)
public void updateAB(TabA a, TabB b) {
tabADAO.updateTabA(a);
tabBDAO.updateTabB(b);
} /**
* 删除指定id的TabA、TabB记录
*
* @param id
* 指定id
*/
// @Transactional(readOnly=false)
public void deleteABif(Long id) {
tabADAO.deleteTabAById(id);
tabBDAO.deleteTabBById(id);
} public void setTabADAO(TabADAO tabADAO) {
this.tabADAO = tabADAO;
} public void setTabBDAO(TabBDAO tabBDAO) {
this.tabBDAO = tabBDAO;
}
}

StuJotmServiceImpl

 <?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:jee="http://www.springframework.org/schema/jee"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> <!--指定Spring配置中用到的属性文件 -->
<bean id="propertyConfig"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
<!-- JOTM实例 -->
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" />
<!-- JTA事务管理器 -->
<bean id="myJtaManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction">
<ref local="jotm" />
</property>
</bean>
<!-- 数据源A -->
<bean id="dataSourceA" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
destroy-method="shutdown">
<property name="dataSource">
<bean class="org.enhydra.jdbc.standard.StandardXADataSource"
destroy-method="shutdown">
<property name="transactionManager" ref="jotm" />
<property name="driverName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
</bean>
</property>
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 数据源B -->
<bean id="dataSourceB" class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
destroy-method="shutdown">
<property name="dataSource">
<bean class="org.enhydra.jdbc.standard.StandardXADataSource"
destroy-method="shutdown">
<property name="transactionManager" ref="jotm" />
<property name="driverName" value="${jdbc2.driver}" />
<property name="url" value="${jdbc2.url}" />
</bean>
</property>
<property name="user" value="${jdbc2.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 事务切面配置 -->
<aop:config>
<aop:pointcut id="serviceOperation" expression="execution(* *..service*..*(..))" />
<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice" />
</aop:config>
<!-- 通知配置 -->
<tx:advice id="txAdvice" transaction-manager="myJtaManager">
<tx:attributes>
<tx:method name="delete*" rollback-for="Exception" />
<tx:method name="save*" rollback-for="Exception" />
<tx:method name="update*" rollback-for="Exception" />
<tx:method name="*" read-only="true" rollback-for="Exception" />
</tx:attributes>
</tx:advice> <!--根据dataSourceA和sql-map-config_A.xml创建一个SqlMapClientA -->
<bean id="sqlMapClientA" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource">
<ref local="dataSourceA" />
</property>
<property name="configLocation">
<value>sql-map-config_A.xml</value>
</property>
</bean>
<!--根据dataSourceB和sql-map-config_B.xml创建一个SqlMapClientB -->
<bean id="sqlMapClientB" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource">
<ref local="dataSourceB" />
</property>
<property name="configLocation">
<value>sql-map-config_B.xml</value>
</property>
</bean>
<!--根据sqlMapClientA创建一个SqlMapClientTemplate的模版类实例sqlMapClientTemplateA -->
<bean id="sqlMapClientTemplateA" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
<property name="sqlMapClient" ref="sqlMapClientA" />
</bean>
<!--根据sqlMapClientB创建一个SqlMapClientTemplate的模版类实例sqlMapClientTemplateB -->
<bean id="sqlMapClientTemplateB" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
<property name="sqlMapClient" ref="sqlMapClientB" />
</bean> <!-- 配置DAO,并注入所使用的sqlMapClientTemplate实例 -->
<bean id="tabADAO" class="com.lavasoft.stu.jtom.dao.impl.TabADAOImpl">
<property name="sqlMapClientTemplate" ref="sqlMapClientTemplateA" />
</bean>
<bean id="tabBDAO" class="com.lavasoft.stu.jtom.dao.impl.TabBDAOImpl">
<property name="sqlMapClientTemplate" ref="sqlMapClientTemplateB" />
</bean> <!-- Service配置,注入DAO -->
<bean id="stuJotmService" class="com.lavasoft.stu.jtom.service.StuJotmServiceImpl">
<property name="tabADAO" ref="tabADAO" />
<property name="tabBDAO" ref="tabBDAO" />
</bean>
</beans>

applicationContext.xml

 jdbc.database=cms_release
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.0.1:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull
jdbc.username=root
jdbc.password=123456 jdbc2.database=cms_release
jdbc2.driver=com.mysql.jdbc.Driver
jdbc2.url=jdbc:mysql://192.168.0.2:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull
jdbc2.username=root
jdbc2.password=123456

jdbc.properties

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <sqlMapConfig>
<settings cacheModelsEnabled="true" enhancementEnabled="true"
lazyLoadingEnabled="true" errorTracingEnabled="true"
useStatementNamespaces="true"/> <sqlMap resource="com/lavasoft/stu/jtom/entity/sqlmap/TabA.xml"/> </sqlMapConfig>

sql-map-config_A.xml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <sqlMapConfig>
<settings cacheModelsEnabled="true" enhancementEnabled="true"
lazyLoadingEnabled="true" errorTracingEnabled="true"
useStatementNamespaces="true"/> <sqlMap resource="com/lavasoft/stu/jtom/entity/sqlmap/TabB.xml"/> </sqlMapConfig>

sql-map-config_B.xml

 public class Test {
private static ApplicationContext ctx = ApplicationContextUtil.getApplicationContext();
private static StuJotmService ser = (StuJotmService) ctx.getBean("stuJotmService"); public static void test_() {
TabA a = new TabA();
a.setId(2L);
a.setName("aaa4");
a.setAddress("address a4"); TabB b = new TabB();
b.setId(3L);
b.setName("bbb3");
b.setAddress("address b5"); ser.saveAB(a, b);
} public static void main(String[] args) {
test_();
}
}

2.3 测试效果

先运行Test文件,可以看到两个库两个表都正常插入值。

再把TabA的setId改为其他任意一个长整型,那么TabB肯定会报主键重复错,因为TabB的setId没改,那么如果事务生效的话,最后应该是两张表都没插入值,如果事务没生效,那么TabA会插入一条新的数据。

2.3 完整结构

完整代码下载:

spring+jotm+ibatis+mysql实现JTA分布式事务的更多相关文章

  1. Springboot+Atomikos+Jpa+Mysql实现JTA分布式事务

    1 前言 之前整理了一个spring+jotm实现的分布式事务实现,但是听说spring3.X后不再支持jotm了,jotm也有好几年没更新了,所以今天整理springboot+Atomikos+jp ...

  2. Spring 3.0 + Atomikos构建jta分布式事务

    Spring3.0已经不再支持jtom了,不过我们可以用第三方开源软件atomikos(http://www.atomikos.com/)来实现.Atomikos是目前在分布式事务管理中做得相当不错的 ...

  3. Springboot + Atomikos + Druid + Mysql 实现JTA分布式事务

    DataSource 配置 package com.cheng.dynamic.config; import java.util.Properties; import javax.sql.DataSo ...

  4. 使用Atomikos Transactions Essentials实现多数据源JTA分布式事务--转载

    原文:http://www.ite/topic/122700 9.17 update:使用NonXADataSourceBean. Mysql在5.0版本和Connecter/J5.0版本后提供了XA ...

  5. Spring Boot2.0之多数据源分布式事务问题

    分布式事务解决方案的问题, 分布式事务产生的原因: 多个不同的服务连接不同的数据源 ,做分布式事务的管理. 这种情况是连接两个数据源的情况,然后事务管理器是这样的 只管理了test02的这端业务代码. ...

  6. springboot学习笔记:10.springboot+atomikos+mysql+mybatis+druid+分布式事务

    前言 上一篇文章我们整合了springboot+druid+mybatis+mysql+多数据源: 本篇文章大家主要跟随你们涛兄在上一届基础上配置一下多数据源情况下的分布式事务: 首先,到底啥是分布式 ...

  7. spring boot:shardingsphere+druid整合seata分布式事务(spring boot 2.3.3)

    一,shardingshpere为什么要整合seata? 分库分表是数据库扩展中最常用的处理方法, shardingshpere作为使用最广泛的分表中间件, 如果不支持分布式事务,则它的数据一致性就会 ...

  8. Spring Cloud Alibaba 使用Seata解决分布式事务

    为什么会产生分布式事务? 随着业务的快速发展,网站系统往往由单体架构逐渐演变为分布式.微服务架构,而对于数据库则由单机数据库架构向分布式数据库架构转变.此时,我们会将一个大的应用系统拆分为多个可以独立 ...

  9. JTA 分布式事务

    什么是JTA - 2009-07-25 18:31:06|  分类: 技术文章|举报|字号 订阅     什么是JTA? Java Transaction API(Java事务API) (JTA)Ja ...

随机推荐

  1. Android调试工具之ADB

    Android调试工具之ADB 1.     什么是ADB adb的全称为Android Debug Bridge,顾名思义,这个是PC机与Android设备的连接桥.简单的说,就是通过adb ,PC ...

  2. hibernate 动态多数据库

    最近老师给了一个任务,需求是这样的 服务器A上有一张表,里面存放了若干个服务器的信息,表的字段包括: private int id; private String serverName; privat ...

  3. C++多重继承与虚拟继承

    本文只是粗浅讨论一下C++中的多重继承和虚拟继承. 多重继承中的构造函数和析构函数调用次序 我们先来看一下简单的例子: #include <iostream> using namespac ...

  4. OpenCV GUI基本操作,回调函数,进度条,裁剪图像等

    代码为转载,出处找不到了,不贴了 工具条进度条: // ConvertColor.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #incl ...

  5. C++语言之静态变量的运用

    #include <iostream> using namespace std ; class Banana { public: static int id ; Banana(void) ...

  6. Http的会话跟踪和跨站攻击(xss)

    会话跟踪 什么是会话? 客户端打开与服务器的连接发出请求到服务器响应客户端请求的全过程称之为会话. 什么是会话跟踪? 会话跟踪指的是对同一个用户对服务器的连续的请求和接受响应的监视. 为什么需要会话跟 ...

  7. How to configure ODBC DSN in Client to access remote DB2 for Windows

      How to configure ODBC DSN in Client to access remote DB2 for Windows MA Gen feng (Guangdong Unito ...

  8. C# /VB.NET 创建PDF项目符号列表和多级编号列表

    使用项目符号和编号,可以让文档的层次结构更清晰.更有条理,也更容易突出重点.在编辑文档的过程中,我个人也比较偏爱项目标号来标注文章重点信息.在之前的文章中,介绍了如何在Word中来创建项目标号和编号列 ...

  9. ELF 文件 动态连接 - 延迟绑定(PLT)

    PLT 全称:Procedure Linkage Table ,直译:过程连接表 由于在动态连接中,程序的模块之间包含了大量的函数引用,所以在程序开始执行前,动态链接会耗费较多的时间用于模块之间函数引 ...

  10. C++——虚函数问题小集

    学习C++ 不可避免地会遇到虚函数的问题,下面几个问题在学习初期或多或少会存在一些疑惑,所以便将其总结了下来. 1.为什么静态成员函数.构造函数不能定义为虚函数? 因为静态成员函数是一个大家共享的一个 ...