假定我们有这样一个需求:当我们新建一个用户的时候需要往一个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、配置文件application.xml
<!--?xml version=1.0 encoding=UTF-8?--> <beans aop="" beans="" http:="" schema="" spring-aop.xsd="" spring-beans.xsd="" spring-tx.xsd="" tx="" www.springframework.org="" xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans"> <!-- 引用Spring内部所提供的对JOTM支持的工厂类 --> <bean class="org.springframework.transaction.jta.JotmFactoryBean" id="jotm"> <!-- 配置JTA事务管理器, 并在管理器中使用上面所配置的JOTM --> <bean class="org.springframework.transaction.jta.JtaTransactionManager" id="txManager"> <property name="userTransaction" ref="jotm"> </property></bean> <!-- 配置多个数据源 --> <bean class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown" id="db1"> <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"> </property></property></property></bean> </property> <property name="user" value="root"> <property name="password" value="root"> </property></property></bean> <bean class="org.enhydra.jdbc.pool.StandardXAPoolDataSource" destroy-method="shutdown" id="db2"> <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"> </property></property></property></bean> </property> <property name="user" value="root"> <property name="password" value="root"> </property></property></bean> <!-- 根据不同的数据源配置两个jdbcTemplate --> <bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate1"> <property name="dataSource" ref="db1"> </property></bean> <bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate2"> <property name="dataSource" ref="db2"> </property></bean> <bean class="com.zdp.dao.UserDao" id="userDao"> <property name="jdbcTemplate" ref="jdbcTemplate1"> </property></bean> <bean class="com.zdp.dao.LogDao" id="logDao"> <property name="jdbcTemplate" ref="jdbcTemplate2"> </property></bean> <bean class="com.zdp.service.UserService" id="userService"> <property name="userDao" ref="userDao"> <property name="logDao" ref="logDao"> </property></property></bean> <!-- JTA事务传播特性 --> <tx:advice id="txAdviceJTA" transaction-manager="txManager"> <tx:attributes> <tx:method isolation="DEFAULT" name="save*" propagation="REQUIRED" rollback-for="Exception/"> <tx:method isolation="DEFAULT" name="add*" propagation="REQUIRED" rollback-for="Exception/"> <tx:method isolation="DEFAULT" name="create*" propagation="REQUIRED" rollback-for="Exception/"> <tx:method isolation="DEFAULT" name="insert*" propagation="REQUIRED" rollback-for="Exception/"> <tx:method isolation="DEFAULT" name="del*" propagation="REQUIRED" rollback-for="Exception/"> <tx:method isolation="DEFAULT" name="update*" propagation="REQUIRED" rollback-for="Exception/"> <tx:method name="*" read-only="true/"> </tx:method></tx:method></tx:method></tx:method></tx:method></tx:method></tx:method></tx:attributes> </tx:advice> </aop:advisor></aop:config> </bean></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 + ')); } }
public class UserTest { @Test public void testSave() { ApplicationContext cxt = new ClassPathXmlApplicationContext(ApplicationContext.xml); UserService us = (UserService) cxt.getBean(userService); us.saveUser(1, zhangsan); } }