本文目录导读:

在 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 设置即可。