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. Vim/Vi常用操作(第二版)

    周围同事不是用vim就是Emacs,你要是用一ultraedit,你都不好意思跟人家打招呼;什么插件呀,语法高亮呀,拼写检查呀,能给它开的都给它开着,就是一个字儿:酷. 你说这么牛B一东西,怎么着学会 ...

  2. LIRe 源代码分析 5:提取特征向量[以颜色布局为例]

    ===================================================== LIRe源代码分析系列文章列表: LIRe 源代码分析 1:整体结构 LIRe 源代码分析 ...

  3. Media Player Classic - HC 源代码分析 7:详细信息选项卡(CPPageFileInfoDetails)

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  4. 解决winform窗体闪烁问题

    如果你在Form中绘图的话,不论是不是采用的双缓存,都会看到图片在更新的时候都会不断地闪烁,解决方法就是在这个窗体的构造函数中增加以下三行代码: 请在构造函数里面底下加上如下几行: SetStyle( ...

  5. 利用可变参实现fprintf函数

    #include <stdio.h> #include <stdarg.h> /* 可变参相关接口 typedef char * va_list ; void va_start ...

  6. myeclipse不编译

    错误: org.eclipse.core.internal.registry.configurationElementHandle cannot be cast to org.eclipse.jdt. ...

  7. c++ list 合并操作函数实例

    #include <list> #include <iostream> using namespace std; //list 链表的打印 void print(list< ...

  8. Android 应用内直接跳转酷市场

    不确定酷市场后期是否还会该包名或者路径,目前的7.9 版本测试通过. private void gotoCoolapkMarket() { try { Intent intent = new Inte ...

  9. 安装centOS后要解决的问题

    1,检查是否联网 ping www.baidu.com 未显示: 则表示网络未连接 首先关闭防火墙 sudo systemctl stop firewalld.service #停止firewall ...

  10. 查找链表中是否有环linked-list-cycle

    Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ext ...