前言
事务管理是保证数据一致性的重要手段。Spring Boot 提供了声明式事务管理,通过@Transactional 注解可以方便地管理事务。本文将详细介绍事务管理的用法和注意事项。
快速开始
1. 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 或 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
2. 启用事务
@SpringBootApplication
@EnableTransactionManagement
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
3. 基本使用
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
@Transactional
public UserDTO create(UserCreateDTO dto) {
User user = new User();
user.setUsername(dto.getUsername());
user.setEmail(dto.getEmail());
return userRepository.save(user);
}
}
@Transactional 详解
1. 注解属性
@Transactional(
propagation = Propagation.REQUIRED, // 传播行为
isolation = Isolation.READ_COMMITTED, // 隔离级别
timeout = 30, // 超时时间(秒)
readOnly = false, // 是否只读
rollbackFor = Exception.class, // 回滚异常
noRollbackFor = ArithmeticException.class // 不回滚异常
)
public void businessMethod() {
// 业务逻辑
}
2. 传播行为
@Service
public class OrderService {
@Autowired
private UserService userService;
/**
* REQUIRED - 默认
* 加入现有事务或创建新事务
*/
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder() {
// 创建订单
userService.updateUser(); // 加入同一事务
}
/**
* REQUIRES_NEW
* 总是创建新事务,挂起现有事务
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logOrder() {
// 记录日志,独立事务
}
/**
* NESTED
* 嵌套事务,保存点
*/
@Transactional(propagation = Propagation.NESTED)
public void nestedMethod() {
// 嵌套事务
}
/**
* SUPPORTS
* 支持事务,没有事务也以非事务运行
*/
@Transactional(propagation = Propagation.SUPPORTS)
public void queryMethod() {
// 查询操作
}
/**
* NOT_SUPPORTED
* 以非事务方式运行,挂起现有事务
*/
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void batchOperation() {
// 批量操作,不需要事务
}
/**
* MANDATORY
* 必须存在事务,否则抛出异常
*/
@Transactional(propagation = Propagation.MANDATORY)
public void mustInTransaction() {
// 必须在事务中调用
}
/**
* NEVER
* 必须在非事务环境下运行
*/
@Transactional(propagation = Propagation.NEVER)
public void noTransaction() {
// 不能在事务中调用
}
}
3. 隔离级别
@Service
public class TransactionService {
/**
* DEFAULT - 使用数据库默认隔离级别
*/
@Transactional(isolation = Isolation.DEFAULT)
public void defaultIsolation() {
// MySQL: REPEATABLE_READ
// Oracle: READ_COMMITTED
}
/**
* READ_UNCOMMITTED - 读未提交
* 可能读到脏数据、不可重复读、幻读
*/
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void readUncommitted() {
// 性能最好,一致性最差
}
/**
* READ_COMMITTED - 读已提交
* 避免脏读,可能不可重复读、幻读
*/
@Transactional(isolation = Isolation.READ_COMMITTED)
public void readCommitted() {
// Oracle 默认,大多数场景适用
}
/**
* REPEATABLE_READ - 可重复读
* 避免脏读、不可重复读,可能幻读
*/
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void repeatableRead() {
// MySQL 默认
}
/**
* SERIALIZABLE - 串行化
* 避免所有并发问题
*/
@Transactional(isolation = Isolation.SERIALIZABLE)
public void serializable() {
// 性能最差,一致性最好
}
}
4. 回滚规则
@Service
public class TransactionService {
/**
* 默认只回滚 RuntimeException 和 Error
*/
@Transactional
public void method1() {
// 抛出 RuntimeException 会回滚
// 抛出 Checked Exception 不会回滚
}
/**
* 指定回滚异常
*/
@Transactional(rollbackFor = Exception.class)
public void method2() {
// 抛出任何 Exception 都会回滚
}
/**
* 指定不回滚异常
*/
@Transactional(noRollbackFor = ArithmeticException.class)
public void method3() {
// 抛出 ArithmeticException 不会回滚
}
/**
* 多个回滚异常
*/
@Transactional(rollbackFor = {IOException.class, SQLException.class})
public void method4() throws IOException, SQLException {
// 抛出指定异常会回滚
}
}
事务失效场景
1. 非 public 方法
@Service
public class UserService {
/**
* ❌ 失效 - 非 public
*/
@Transactional
protected void method1() {
// 事务失效
}
/**
* ✅ 正确
*/
@Transactional
public void method2() {
// 事务生效
}
}
2. 自调用
@Service
public class UserService {
/**
* ❌ 失效 - 自调用
*/
public void method1() {
method2(); // 事务失效
}
@Transactional
public void method2() {
// 事务失效
}
/**
* ✅ 正确 - 通过代理调用
*/
@Autowired
@Lazy
private UserService self;
public void method3() {
self.method4(); // 事务生效
}
@Transactional
public void method4() {
// 事务生效
}
}
3. 异常被捕获
@Service
public class UserService {
/**
* ❌ 失效 - 异常被捕获
*/
@Transactional
public void method1() {
try {
// 业务逻辑
} catch (Exception e) {
log.error("错误", e);
// 异常被捕获,不会回滚
}
}
/**
* ✅ 正确 - 重新抛出异常
*/
@Transactional
public void method2() {
try {
// 业务逻辑
} catch (Exception e) {
log.error("错误", e);
throw new RuntimeException(e); // 重新抛出
}
}
}
4. 错误配置
@Service
public class UserService {
/**
* ❌ 失效 - 异常类型不匹配
*/
@Transactional(rollbackFor = IOException.class)
public void method1() throws SQLException {
// 抛出 SQLException 不会回滚
}
/**
* ✅ 正确
*/
@Transactional(rollbackFor = Exception.class)
public void method2() throws SQLException {
// 抛出 SQLException 会回滚
}
}
编程式事务
1. 使用 TransactionTemplate
@Service
@RequiredArgsConstructor
public class TransactionService {
private final TransactionTemplate transactionTemplate;
public void createOrder(Order order) {
transactionTemplate.execute(status -> {
try {
// 业务逻辑
orderRepository.save(order);
inventoryService.decrease(order.getProductId(), order.getQuantity());
return order;
} catch (Exception e) {
status.setRollbackOnly();
throw e;
}
});
}
}
2. 使用 PlatformTransactionManager
@Service
@RequiredArgsConstructor
public class TransactionService {
private final PlatformTransactionManager transactionManager;
public void createOrder(Order order) {
TransactionStatus status = transactionManager.getTransaction(
new DefaultTransactionDefinition()
);
try {
// 业务逻辑
orderRepository.save(order);
inventoryService.decrease(order.getProductId(), order.getQuantity());
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}
最佳实践
1. 事务粒度
// ✅ 推荐 - 合理的事务粒度
@Service
public class OrderService {
@Transactional
public void createOrder(OrderCreateDTO dto) {
// 创建订单
Order order = createOrder(dto);
// 扣减库存
inventoryService.decrease(dto.getProductId(), dto.getQuantity());
// 更新用户积分
userService.addPoints(dto.getUserId(), dto.getPoints());
}
}
// ❌ 不推荐 - 事务粒度过大
@Service
public class OrderService {
@Transactional
public void processEverything() {
// 创建订单
// 扣减库存
// 更新积分
// 发送短信
// 发送邮件
// ... 太多操作在一个事务中
}
}
2. 只读事务
@Service
public class QueryService {
/**
* 只读事务,性能更好
*/
@Transactional(readOnly = true)
public List<Order> findAll() {
return orderRepository.findAll();
}
/**
* 只读事务
*/
@Transactional(readOnly = true)
public Order findById(Long id) {
return orderRepository.findById(id).orElse(null);
}
}
3. 超时设置
@Service
public class BatchService {
/**
* 设置超时时间
*/
@Transactional(timeout = 60)
public void batchInsert(List<Order> orders) {
for (Order order : orders) {
orderRepository.save(order);
}
}
}
4. 嵌套事务
@Service
public class ParentService {
@Autowired
private ChildService childService;
@Transactional
public void parentMethod() {
// 父事务
try {
childService.childMethod(); // 子事务
} catch (Exception e) {
// 子事务回滚,父事务可以选择不回滚
}
}
}
@Service
public class ChildService {
@Transactional(propagation = Propagation.NESTED)
public void childMethod() {
// 子事务,有独立的保存点
}
}
总结
事务管理要点:
- ✅ @Transactional - 声明式事务
- ✅ 传播行为 - REQUIRED、REQUIRES_NEW、NESTED 等
- ✅ 隔离级别 - READ_COMMITTED、REPEATABLE_READ 等
- ✅ 回滚规则 - rollbackFor、noRollbackFor
- ✅ 失效场景 - 非 public、自调用、异常捕获
- ✅ 编程式事务 - TransactionTemplate
良好的事务管理,能保证数据的一致性和完整性。