javax.transaction包完整教程:分布式事务管理与Java代码实例

2024-06-21 李腾 79 次阅读 0 次点赞
本文深入讲解Java事务API(JTA)中javax.transaction包的核心功能,详细分析UserTransaction、TransactionManager等关键接口的使用方法,通过银行转账、事务状态检查等多个完整代码示例展示分布式事务管理的实现技巧,同时对比现代Spring声明式事务管理方案,为Java开发者提供全面的分布式事务解决方案。

javax.transaction包是Java事务API(JTA)的核心部分,提供了分布式事务管理的接口和类。它允许应用程序在多个资源管理器(如数据库、消息队列等)之间执行原子性操作。

核心接口和类

1、UserTransaction - 应用程序级事务控制接口

2、TransactionManager - 事务管理器接口

3、Transaction - 代表单个事务

4、Status - 事务状态常量

5、Synchronization - 事务同步回调接口

示例代码

1. 基本UserTransaction使用

import javax.transaction.*;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class BasicTransactionExample {
    
    public void transferMoney(Connection conn1, Connection conn2, 
                             String fromAccount, String toAccount, double amount) {
        UserTransaction ut = null;
        
        try {
            // 获取UserTransaction实例
            ut = (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");
            
            // 开始事务
            ut.begin();
            
            // 执行第一个数据库操作 - 扣款
            String sql1 = "UPDATE accounts SET balance = balance - ? WHERE account_id = ?";
            PreparedStatement ps1 = conn1.prepareStatement(sql1);
            ps1.setDouble(1, amount);
            ps1.setString(2, fromAccount);
            ps1.executeUpdate();
            
            // 执行第二个数据库操作 - 存款
            String sql2 = "UPDATE accounts SET balance = balance + ? WHERE account_id = ?";
            PreparedStatement ps2 = conn2.prepareStatement(sql2);
            ps2.setDouble(1, amount);
            ps2.setString(2, toAccount);
            ps2.executeUpdate();
            
            // 提交事务
            ut.commit();
            System.out.println("转账成功");
            
        } catch (Exception e) {
            try {
                if (ut != null) {
                    ut.rollback();
                }
                System.out.println("转账失败,已回滚");
            } catch (SystemException se) {
                se.printStackTrace();
            }
            e.printStackTrace();
        }
    }
}

2. 使用TransactionManager

import javax.transaction.*;
import javax.naming.InitialContext;

public class TransactionManagerExample {
    
    private TransactionManager tm;
    
    public TransactionManagerExample() {
        try {
            tm = (TransactionManager) new InitialContext().lookup("java:comp/TransactionManager");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void performTransactionalOperation(Runnable operation) {
        try {
            // 开始事务
            tm.begin();
            
            // 获取当前事务
            Transaction transaction = tm.getTransaction();
            
            // 注册同步回调
            transaction.registerSynchronization(new CustomSynchronization());
            
            // 执行业务操作
            operation.run();
            
            // 提交事务
            tm.commit();
            
        } catch (Exception e) {
            try {
                tm.rollback();
            } catch (SystemException se) {
                se.printStackTrace();
            }
            e.printStackTrace();
        }
    }
    
    // 自定义同步回调
    private static class CustomSynchronization implements Synchronization {
        @Override
        public void beforeCompletion() {
            System.out.println("事务即将完成,准备提交前的清理工作");
        }
        
        @Override
        public void afterCompletion(int status) {
            if (status == Status.STATUS_COMMITTED) {
                System.out.println("事务已提交,执行后续操作");
            } else if (status == Status.STATUS_ROLLEDBACK) {
                System.out.println("事务已回滚,执行补偿操作");
            }
        }
    }
}

3. 事务状态检查

import javax.transaction.*;

public class TransactionStatusChecker {
    
    public void checkTransactionStatus(UserTransaction ut) {
        try {
            int status = ut.getStatus();
            
            switch (status) {
                case Status.STATUS_ACTIVE:
                    System.out.println("事务正在进行中");
                    break;
                case Status.STATUS_COMMITTED:
                    System.out.println("事务已提交");
                    break;
                case Status.STATUS_ROLLEDBACK:
                    System.out.println("事务已回滚");
                    break;
                case Status.STATUS_NO_TRANSACTION:
                    System.out.println("没有活动的事务");
                    break;
                case Status.STATUS_PREPARING:
                    System.out.println("事务正在准备");
                    break;
                case Status.STATUS_PREPARED:
                    System.out.println("事务已准备就绪");
                    break;
                case Status.STATUS_COMMITTING:
                    System.out.println("事务正在提交");
                    break;
                case Status.STATUS_ROLLING_BACK:
                    System.out.println("事务正在回滚");
                    break;
                case Status.STATUS_MARKED_ROLLBACK:
                    System.out.println("事务已标记为回滚");
                    break;
                default:
                    System.out.println("未知事务状态: " + status);
            }
            
        } catch (SystemException e) {
            e.printStackTrace();
        }
    }
    
    public void setRollbackOnly(UserTransaction ut) {
        try {
            ut.setRollbackOnly();
            System.out.println("事务已标记为仅回滚");
        } catch (SystemException e) {
            e.printStackTrace();
        }
    }
}

4. 完整的银行转账示例

import javax.transaction.*;
import javax.sql.DataSource;
import javax.naming.InitialContext;
import java.sql.Connection;
import java.sql.PreparedStatement;

public class BankTransferService {
    
    private DataSource dataSource;
    private UserTransaction userTransaction;
    
    public BankTransferService() {
        try {
            InitialContext ctx = new InitialContext();
            dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/BankDB");
            userTransaction = (UserTransaction) ctx.lookup("java:comp/UserTransaction");
        } catch (Exception e) {
            throw new RuntimeException("初始化失败", e);
        }
    }
    
    public boolean transfer(String fromAccount, String toAccount, double amount) {
        Connection conn = null;
        
        try {
            // 开始事务
            userTransaction.begin();
            
            conn = dataSource.getConnection();
            
            // 检查余额是否足够
            if (!hasSufficientBalance(conn, fromAccount, amount)) {
                userTransaction.rollback();
                return false;
            }
            
            // 执行转账操作
            withdraw(conn, fromAccount, amount);
            deposit(conn, toAccount, amount);
            
            // 记录交易
            logTransaction(conn, fromAccount, toAccount, amount);
            
            // 提交事务
            userTransaction.commit();
            return true;
            
        } catch (Exception e) {
            try {
                userTransaction.rollback();
            } catch (SystemException se) {
                se.printStackTrace();
            }
            e.printStackTrace();
            return false;
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    private boolean hasSufficientBalance(Connection conn, String account, double amount) 
            throws Exception {
        String sql = "SELECT balance FROM accounts WHERE account_id = ?";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setString(1, account);
            var rs = ps.executeQuery();
            if (rs.next()) {
                return rs.getDouble("balance") >= amount;
            }
            return false;
        }
    }
    
    private void withdraw(Connection conn, String account, double amount) throws Exception {
        String sql = "UPDATE accounts SET balance = balance - ? WHERE account_id = ?";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setDouble(1, amount);
            ps.setString(2, account);
            ps.executeUpdate();
        }
    }
    
    private void deposit(Connection conn, String account, double amount) throws Exception {
        String sql = "UPDATE accounts SET balance = balance + ? WHERE account_id = ?";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setDouble(1, amount);
            ps.setString(2, account);
            ps.executeUpdate();
        }
    }
    
    private void logTransaction(Connection conn, String fromAccount, 
                              String toAccount, double amount) throws Exception {
        String sql = "INSERT INTO transactions (from_account, to_account, amount, timestamp) " +
                    "VALUES (?, ?, ?, CURRENT_TIMESTAMP)";
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setString(1, fromAccount);
            ps.setString(2, toAccount);
            ps.setDouble(3, amount);
            ps.executeUpdate();
        }
    }
}

注意事项

1、环境依赖: JTA通常需要Java EE应用服务器支持,如WebLogic、WebSphere或JBoss

2、资源查找: 事务管理器通常通过JNDI查找获取

3、异常处理: 必须妥善处理事务回滚

4、超时设置: 可以通过setTransactionTimeout方法设置事务超时时间

现代替代方案

在现代Java应用中,通常使用Spring框架的声明式事务管理,它提供了更简洁的事务管理方式:

@Transactional
public void transferMoney(String fromAccount, String toAccount, double amount) {
    // 业务逻辑
}

javax.transaction包为分布式事务提供了标准API,但在实际开发中,建议使用框架提供的高级抽象来简化事务管理。

本文由人工编写,AI优化,转载请注明原文地址: Java JTA事务管理:javax.transaction使用详解与实战代码示例

评论 (1)

登录后发表评论
小草莓2025-12-01 18:57:23
示例代码很清晰,特别是转账的例子,让我对UserTransaction的实际使用有了直观理解。感谢作者分享,想请教一下在Spring Boot项目中如何整合JTA管理多数据源事务?