目录
两阶段提交
图解

Atomikos是一个非常流行的开源事务管理器,并且可以嵌入到你的Spring Boot应用中。Tomcat应用服务器没有实现JTA规范,当使用Tomcat作为应用服务器的时候,需要使用第三方的事务管理器类来作为全局的事务管理器,而Atomikos框架就是这个作用,将事务管理整合到应用中,而不依赖于application server。
Atomikos核心类
1、数据源定义:com.atomikos.jdbc.AtomikosDataSourceBean

2、atomikos提供的javax.transaction.UserTransaction接口实现类com.atomikos.icatch.jta.UserTransactionImp来开启、提交、回滚事务。

实现代码
- public class AtomikosExample {
- private static AtomikosDataSourceBean createAtomikosDataSourceBean(String dbName) {
- // 连接池基本属性
- Properties p = new Properties();
- p.setProperty("url", "jdbc:mysql://localhost:3306/" + dbName);
- p.setProperty("user", "root");
- p.setProperty("password", "root");
-
- // 使用AtomikosDataSourceBean封装com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
- AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
- // atomikos要求为每个AtomikosDataSourceBean名称,为了方便记忆,这里设置为和dbName相同
- ds.setUniqueResourceName(dbName);
- ds.setXaDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");
- ds.setXaProperties(p);
- return ds;
- }
-
- public static void main(String[] args) {
- AtomikosDataSourceBean ds1 = createAtomikosDataSourceBean("test2022");
- AtomikosDataSourceBean ds2 = createAtomikosDataSourceBean("test2021");
-
- Connection conn1 = null;
- Connection conn2 = null;
- PreparedStatement ps1 = null;
- PreparedStatement ps2 = null;
-
- UserTransaction userTransaction = new UserTransactionImp();
- try {
- // 开启事务
- userTransaction.begin();
-
- // 执行db1上的sql
- conn1 = ds1.getConnection();
- ps1 = conn1.prepareStatement("INSERT into user(name) VALUES (?)", Statement.RETURN_GENERATED_KEYS);
- ps1.setString(1, "zhangsan");
- ps1.executeUpdate();
- ResultSet generatedKeys = ps1.getGeneratedKeys();
- int userId = -1;
- while (generatedKeys.next()) {
- // 获得自动生成的userId
- userId = generatedKeys.getInt(1);
- }
-
- // 模拟异常 ,直接进入catch代码块,2个都不会提交
- // int i=1/0;
-
- // 执行db2上的sql
- conn2 = ds2.getConnection();
- ps2 = conn2.prepareStatement("INSERT into account(user_id,money) VALUES (?,?)");
- ps2.setInt(1, userId);
- ps2.setDouble(2, 10000000);
- ps2.executeUpdate();
-
- // 两阶段提交
- userTransaction.commit();
- } catch (Exception e) {
- try {
- System.out.println("有异常,所有数据源都回滚");
- userTransaction.rollback();
- } catch (SystemException e1) {
- e1.printStackTrace();
- }
- } finally {
- try {
- ps1.close();
- ps2.close();
- conn1.close();
- conn2.close();
- ds1.close();
- ds2.close();
- } catch (Exception ignore) {
- }
- }
- }
- }
注:新建的maven项目,是依赖Java JDK

需要手动导入javax
使用其声明式事务管理功能来完成事务功能。一般使用的步骤如下:
1、配置事务管理器。spring提供了PlatformTransactionManager接口,其有2个重要的实现类。
2、在需要开启的事务的bean的方法上添加@Transitional注解

配置文件,去配置分布式事务管理器JtaTransactionManager

一个事务方法,涉及两个数据源
- public class JTAService {
- @Autowired
- private UserMapper userMapper;
- @Autowired
- private AccountMapper accountMapper;
-
- @Transactional(rollbackFor = Throwable.class)
- public void insert() {
- User user = new User();
- user.setName("张三");
- userMapper.insert(user);
-
- // 模拟异常
- // int i = 1 / 0;
- Account account = new Account();
- account.setUserId(user.getId());
- account.setMoney(123456789);
- accountMapper.insert(account);
- }
- }
执行启动代码
- ApplicationContext context = new ClassPathXmlApplicationContext("spring-atomikos.xml");
- JTAService jtaService = context.getBean("jtaService", JTAService.class);
- jtaService.insert();
注:依赖spring版本4.3.7.RELEASE
事务注解被事务拦截器拦截后,调用代理对象的invoke方法org.springframework.transaction.interceptor.TransactionInterceptor#invoke

核心框架执行org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

开启一个JTA事务:com.atomikos.icatch.jta.TransactionManagerImp#begin(int)

事务初始状态

底层管理