Java案例怎么实现事务控制?

wen java案例 25

本文目录导读:

Java案例怎么实现事务控制?

  1. 声明式事务(最常用,推荐)
  2. 编程式事务(灵活但代码冗余)
  3. 纯 JDBC 事务(最底层,了解即可)
  4. 事务失效的常见原因(面试/排错高频)
  5. 总结选择

在 Java 中实现事务控制主要有两种方式:声明式事务(主流推荐)和 编程式事务,下面从最常见的 Spring + MyBatis/Spring Data JPA 场景展开,也会提一下纯 JDBC 的基础写法。


声明式事务(最常用,推荐)

使用 @Transactional 注解,Spring 自动管理事务的开启、提交、回滚。

依赖准备(Spring Boot + MyBatis)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

配置类(一般自动配置,无需额外写)

@Configuration
@EnableTransactionManagement  // 开启事务管理(Spring Boot 默认已开启)
public class AppConfig {
    // 数据源、事务管理器通常由 Spring Boot 自动配置
}

业务层使用 @Transactional

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AccountMapper accountMapper;
    @Override
    @Transactional(rollbackFor = Exception.class)  // 遇到任何异常都回滚
    public void transfer(Long fromUserId, Long toUserId, BigDecimal amount) {
        // 扣钱
        accountMapper.decreaseBalance(fromUserId, amount);
        // 模拟异常(强制回滚)
        if (true) {
            throw new RuntimeException("转账失败,触发回滚");
        }
        // 加钱(不会执行)
        accountMapper.increaseBalance(toUserId, amount);
    }
}

关键点:

  • rollbackFor = Exception.class:默认只回滚 RuntimeException,建议显式指定。
  • 同一个类内部方法调用 @Transactional 会失效(需要注入自身或使用 AopContext)。

编程式事务(灵活但代码冗余)

适用于需要精细控制事务边界或无法使用注解的场景。

使用 TransactionTemplate(推荐)

@Service
public class TransferService {
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private UserMapper userMapper;
    public void transfer(Long from, Long to, BigDecimal amount) {
        transactionTemplate.execute(status -> {
            try {
                userMapper.decrease(from, amount);
                // 模拟异常
                if (true) throw new RuntimeException();
                userMapper.increase(to, amount);
                return null;
            } catch (Exception e) {
                status.setRollbackOnly();  // 手动标记回滚
                throw e;
            }
        });
    }
}

使用 PlatformTransactionManager(原始方式)

@Autowired
private PlatformTransactionManager transactionManager;
@Autowired
private TransactionDefinition transactionDefinition;
public void transfer() {
    TransactionStatus status = transactionManager.getTransaction(transactionDefinition);
    try {
        // 业务操作
        userMapper.decrease(from, amount);
        userMapper.increase(to, amount);
        transactionManager.commit(status);
    } catch (Exception e) {
        transactionManager.rollback(status);
        throw e;
    }
}

纯 JDBC 事务(最底层,了解即可)

Connection conn = null;
try {
    conn = dataSource.getConnection();
    conn.setAutoCommit(false);  // 关闭自动提交
    // 多个 SQL 操作
    PreparedStatement ps1 = conn.prepareStatement("UPDATE account SET balance = balance - ? WHERE id = ?");
    ps1.setBigDecimal(1, amount);
    ps1.setLong(2, fromUserId);
    ps1.executeUpdate();
    PreparedStatement ps2 = conn.prepareStatement("UPDATE account SET balance = balance + ? WHERE id = ?");
    ps2.setBigDecimal(1, amount);
    ps2.setLong(2, toUserId);
    ps2.executeUpdate();
    conn.commit();  // 提交
} catch (Exception e) {
    if (conn != null) conn.rollback();  // 回滚
    throw e;
} finally {
    if (conn != null) conn.close();
}

事务失效的常见原因(面试/排错高频)

原因 解决
@Transactional 加到 private 方法 改为 public
同类内部方法调用(this.method() 注入自身或 AopContext.currentProxy()
异常被 try-catch 吞掉 抛出异常或手动 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
数据库引擎不支持事务(如 MyISAM) 改为 InnoDB
rollbackFor 未包含自定义异常 显式指定 rollbackFor = Exception.class

总结选择

方式 适用场景
@Transactional 绝大多数业务场景,简单清晰
TransactionTemplate 需要灵活控制事务边界(如循环中批量提交)
纯 JDBC 非 Spring 项目或底层框架开发
JTA(Java Transaction API) 分布式事务(多个数据源/消息队列)

如果只是做常规的 Spring Boot 项目,优先使用 @Transactional 注解,配合 rollbackFor 设置即可。

抱歉,评论功能暂时关闭!