Spring Boot 中的事务管理:默认配置、失效场景及集中配置
Spring Boot 提供了强大的事务管理功能,基于 Spring 的 @Transactional
注解。本文将详细介绍事务的默认配置、事务失效的常见场景、以及事务的几种集中配置方式,并给出相应的代码片段。
一、事务的默认配置
在 Spring Boot 中,默认情况下,事务管理器会自动配置一个 DataSourceTransactionManager
,前提是项目中已经配置了一个数据源(DataSource
)。以下是一些默认行为:
-
传播行为 :
1. 默认传播行为是Propagation.REQUIRED
,即如果当前存在事务,则加入该事务;否则创建一个新的事务。 -
隔离级别 :
- 默认隔离级别是
Isolation.DEFAULT
,即使用底层数据库的默认隔离级别。
- 默认隔离级别是
-
回滚规则 :
- 默认情况下,只有未捕获的
RuntimeException
和Error
会触发事务回滚。 - 检查型异常(Checked Exception)不会触发回滚。
- 默认情况下,只有未捕获的
-
只读属性 :
- 默认情况下,事务不是只读的。
-
超时时间 :
- 默认没有设置超时时间。
二、事务失效的常见场景
尽管 @Transactional
注解非常方便,但在某些情况下,事务可能不会按预期工作。以下是常见的事务失效场景:
1. 方法为 private
或 final
- Spring 的事务管理是基于 AOP 实现的,AOP 使用动态代理来拦截方法调用。如果方法是
private
或final
,则无法被代理,事务将失效。
@Service
public class UserService {
@Transactional
private void updateUser() {
// 这里的事务不会生效
}
}
2. 同一个类中的方法调用
如果在一个类中,一个非事务方法调用了一个带有 @Transactional
注解的方法,事务也不会生效。因为代理对象不会拦截内部方法调用。
@Service
public class UserService {
public void outerMethod() {
innerMethod(); // 这里事务不会生效
}
@Transactional
public void innerMethod() {
// 事务逻辑
}
}
3. 异常被捕获
如果在事务方法中捕获了异常并处理了它,事务不会回滚。
@Service
public class UserService {
@Transactional
public void updateUser() {
try {
// 业务逻辑
throw new RuntimeException("Error");
} catch (Exception e) {
// 异常被捕获,事务不会回滚
}
}
}
4. 事务方法抛出检查型异常
默认情况下,只有未捕获的 RuntimeException
和 Error
会触发回滚。如果事务方法抛出的是检查型异常(Checked Exception),事务不会回滚
@Service
public class UserService {
@Transactional
public void updateUser() throws IOException {
throw new IOException("Checked Exception"); // 不会触发回滚
}
}
三、事务的集中配置及使用场景
Spring Boot 提供了多种事务配置方式,可以根据不同的需求进行选择。
1. 基于注解的事务配置
这是最常见的事务配置方式,使用 @Transactional
注解即可。
使用场景:
简单的事务管理,适用于大多数业务场景。
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(User user) {
userRepository.save(user);
if (user.getName().equals("error")) {
throw new RuntimeException("Simulated error");
}
}
}
2. 基于 XML 配置的事务管理
虽然 Spring Boot 推荐使用注解,但仍然可以通过 XML 配置事务管理。
使用场景
适用于遗留系统或需要更细粒度控制的场景。
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="create*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceOperation" expression="execution(* com.example.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
</aop:config>
3. 编程式事务管理
通过 TransactionTemplate
手动控制事务。
使用场景:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED, timeout = 10)
public void createUser(User user) {
userRepository.save(user);
}
@Transactional(readOnly = true)
public List<User> getAllUsers() {
return userRepository.findAll();
}
}
四、总结
Spring Boot 提供了灵活且强大的事务管理机制,默认配置可以满足大部分场景的需求。但在实际开发中,需要注意事务失效的常见场景,并根据业务需求选择合适的事务配置方式。
- 默认配置 :适用于大多数简单场景。
- 失效场景 :注意方法访问修饰符、异常处理、同一类方法调用等问题。
- 集中配置 :可以根据需求选择注解、XML、编程式或自定义事务属性的方式。