Java事务(七) - 分布式事务 - spring + JTA + jotm
一. 前言:
在写这篇博客之前,我们需要弄清楚两个概念:本地事务和分布式事务。
本地事务:只处理单一数据源,比如单个数据库。
分布式事务:处理多种异构的数据源, 比如某个业务操作中同时包含JDBC和JMS或者某个操作需要访问多个不同的数据库。
Java通过JTA完成分布式事务, JTA本身只是一种规范, 本篇博客将使用JOTM作为实现, 后续还会使用Atomikos实现。
二. 业务背景:
假定我们有这样一个需求:当我们新建一个用户的时候需要往一个DB中插入一条用户记录,还需要往另一个DB中记录日志
因为是不同的DB操作,所以这里就涉及到分布式事务的处理。
三. 代码实现:
1. 代码结构图:
2. 建表语句:
create database log; DROP TABLE IF EXISTS `log`; CREATE TABLE `log` ( `id` varchar(20) NOT NULL, `content` varchar(100) default NULL, PRIMARY KEY (`id`) ); create database user; DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` varchar(20) NOT NULL, `name` varchar(40) default NULL, PRIMARY KEY (`id`) );
3. 配置文件ApplicationContext.xml
<?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: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.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 引用Spring内部所提供的对JOTM支持的工厂类 --> <bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean" /> <!-- 配置JTA事务管理器, 并在管理器中使用上面所配置的JOTM --> <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="userTransaction" ref="jotm" /> </bean> <!-- 配置多个数据源 --> <bean id="db1" 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="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:MySQL://localhost:3306/user" /> </bean> </property> <property name="user" value="root" /> <property name="password" value="root" /> </bean> <bean id="db2" 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="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:MySQL://localhost:3306/log" /> </bean> </property> <property name="user" value="root" /> <property name="password" value="root" /> </bean> <!-- 根据不同的数据源配置两个jdbcTemplate --> <bean id="jdbcTemplate1" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="db1" /> </bean> <bean id="jdbcTemplate2" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="db2" /> </bean> <bean id="userDao" class="com.zdp.dao.UserDao"> <property name="jdbcTemplate" ref="jdbcTemplate1" /> </bean> <bean id="logDao" class="com.zdp.dao.LogDao"> <property name="jdbcTemplate" ref="jdbcTemplate2" /> </bean> <bean id="userService" class="com.zdp.service.UserService"> <property name="userDao" ref="userDao" /> <property name="logDao" ref="logDao" /> </bean> <!-- JTA事务传播特性 --> <tx:advice id="txAdviceJTA" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="create*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="del*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="*" read-only="true"/> </tx:attributes> </tx:advice> <aop:config> <aop:advisor pointcut="execution(* com.zdp.service..*(..))" advice-ref="txAdviceJTA" /> </aop:config> </beans>
4. service业务类:
public class UserService { private UserDao userDao; private LogDao logDao; public void saveUser(String id, String name) { userDao.insertUser(id, name); // int i = 1 / 0; // 制造异常 logDao.insertLog(id, id + "_" + name); } public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } public LogDao getLogDao() { return logDao; } public void setLogDao(LogDao logDao) { this.logDao = logDao; } }
5. Dao类:
public class UserDao extends JdbcDaoSupport { public void insertUser(String id, String name) { JdbcTemplate template = getJdbcTemplate(); template.execute("insert into user values('" + id + "','" + name + "')"); } }
public class LogDao extends JdbcDaoSupport { public void insertLog(String id, String content) { JdbcTemplate template = getJdbcTemplate(); template.execute("insert into log values('" + id + "','" + content + "')"); } }
6. 测试类:
public class UserTest { @Test public void testSave() { ApplicationContext cxt = new ClassPathXmlApplicationContext("ApplicationContext.xml"); UserService us = (UserService) cxt.getBean("userService"); us.saveUser("1", "zhangsan"); } }
源码下载: http://download.csdn.net/detail/zdp072/7950383
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。