java分布式事务1—— spring + JTA + jotm

业务背景:

假定我们有这样一个需求:当我们新建一个用户的时候需要往一个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 + '));
    }
}



6、测试类:

public class UserTest {
    @Test
    public void testSave() {
        ApplicationContext cxt = new ClassPathXmlApplicationContext(ApplicationContext.xml);
        UserService us = (UserService) cxt.getBean(userService);
        us.saveUser(1, zhangsan);
    }
}




你可能感兴趣的:(分布式,事务)