本文目录导读:

在 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 设置即可。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播