当调用使用 @Transactional 注解的方法时,Spring Boot利用事务管理器来创建或加入事务。事务管理器监视事务的生命周期,根据操作结果进行提交或回滚。
事务隔离级别
Spring Boot支持各种事务隔离级别,包括READ_UNCOMMITTED(读取未提交的数据)、READ_COMMITTED(读取已提交的数据)、REPEATABLE_READ(可重复读)、SERIALIZABLE(串行化)。这些级别确定事务如何与其他事务和底层数据交互。根据应用程序的需求选择正确的隔离级别。
java
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
jj@Transactional
public void updateUser(String username, String email) {
User user = userRepository.findByUsername(username);
user.setEmail(email);
// ... other operations
}
}
在上面的示例中,updateUser() 被标记为 @Transactional,允许Spring Boot管理事务的行为。
理解事务传播
事务行为可以根据方法的注解方式而有所不同。以下是一个关键区别:
@Transactional vs. @Transactional(propagation = Propagation.REQUIRES_NEW)
- @Transactional 创建或加入一个事务。
- @Transactional(propagation = Propagation.REQUIRES_NEW)
创建一个新的事务,如果当前存在事务,则将其挂起。
java
@Service
public class MyService {
@Transactional
public void methodA() {
// ... some code here
methodB();
// ... some code here
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// ... some code here
}
}
在这个例子中,methodA() 调用了 methodB()。由于 REQUIRES_NEW 传播设置,当 methodB() 开始一个新的事务时,methodA() 的事务被挂起。
在同一类内处理事务
当一个 @Transactional 方法调用同一类内的另一个 @Transactional 方法时,Spring 的默认行为值得注意:
默认行为
默认情况下,Spring 使用一种"基于代理"的方法。如果一个 @Transactional 方法调用同一类内的另一个 @Transactional 方法,事务行为不会被应用。
java
@Service
public class MyService {
@Autowired
private MyService self;
ja @Transactional
public void methodA() {
// ... some code here
self.methodB();
// ... some code here
}
@Transactional
public void methodB() {
// ... some code here
}
}
在这个例子中,methodA() 和 methodB() 都被标记为 @Transactional。然而,由于"基于代理"的方法,当从 methodA() 调用 methodB() 时,事务行为不会被应用。为了解决这个问题,可以考虑使用基于AspectJ的织入(weaving)或将 @Transactional 方法移到一个单独的类中。
跨不同Bean管理事务
当调用另一个Bean上的方法时,Spring会在目标Bean周围创建一个新的代理,使其能够管理事务行为:
java
@Service
public class MyService {
@Autowired
private OtherService otherService;
@Transactional
public void methodA() {
// ... some code here
otherService.methodB();
// ... some code here
}
}
@Service
public class OtherService {
@Transactional
public void methodB() {
// ... some code here
}
}
在这个例子中,methodA() 在一个不同的Bean(OtherService)上调用了 methodB()。Spring会在 OtherService 周围创建一个新的代理,以根据 methodA() 的传播设置应用事务行为。
处理未检查的异常
当一个 @Transactional 方法抛出未检查的异常时,Spring 默认情况下会自动回滚事务。这确保如果发生错误,事务内的数据更改不会被持久化。
java
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
public void updateUser(String username, String email) {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new RuntimeException("User not found");
}
user.setEmail(email);
userRepository.save(user);
throw new RuntimeException("Something went wrong");
}
}
在这个例子中,updateUser() 被标记为 @Transactional 并抛出一个未检查的异常。默认情况下,事务将回滚,丢弃对用户电子邮件地址所做的更改。
自定义回滚行为
您可以使用 @Transactional 注解的 rollbackFor 或 noRollbackFor 属性来自定义回滚行为。
java
@Service
@Transactional(noRollbackFor = RuntimeException.class)
public class UserService {
// ...
}
在这个例子中,我们指定 RuntimeException 不应触发回滚。这在您希望在事务内保留更改,即使发生错误时也很有用。
默认的回滚行为
默认情况下,@Transactional 方法在任何未检查的异常发生时都会回滚事务。使用 rollbackFor 或 noRollbackFor 属性来自定义此行为。
私有方法和 @Transactional
@Transactional 仅在公共方法上工作。Spring在公共方法周围创建代理以管理事务行为。私有方法对代理不可见,无法被包装在事务上下文中。
java
@Service
public class MyService {
@Transactional
public void methodA() {
// ... some code here
methodB();
// ... some code here
}
private void methodB() {
// ... some code here
}
}
在这个例子中,methodA() 被标记为 @Transactional,但 methodB() 没有。要启用 methodB() 的事务行为,将其设置为公共方法,或将 @Transactional 注解移到同时调用 methodA() 和 methodB() 的方法上。
处理并发问题
Spring Boot 的 @Transactional 注解通过串行化事务提供了处理并发问题的机制。默认的隔离级别通过确保事务不相互干扰来防止大多数并发问题。
java
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void updateUser(String username, String email) {
User user = userRepository.findByUsername(username);
user.setEmail(email);
// ... other operations
}
}
在这个例子中,updateUser() 被标记为 @Transactional,并且Spring确保当多个线程同时尝试修改同一用户的电子邮件地址时,事务是串行化的。这可以防止数据不一致和竞态条件。
请记住,Spring 中 @Transactional 使用的默认隔离级别是 Isolation.DEFAULT,它与底层数据源的默认值一致。这通常导致"读已提交"的隔离级别,适用于大多数数据库。
精通 @Transactional 对于在Spring Boot应用程序中进行有效的事务管理非常重要。