118
社区成员




作者平台:
| CSDN:https://blog.csdn.net/qq/_41153943%EF%BC%88ID%EF%BC%9A%E6%B1%9F%E5%A4%8F%E3%80%81)
| 掘金:https://juejin.cn/user/651387938290686%EF%BC%88ID%EF%BC%9Ajiangxia/_1024)
| 知乎:https://www.zhihu.com/people/1024-paper-96%EF%BC%88ID%EF%BC%9A%E6%B1%9F%E5%A4%8F)
| GitHub:https://github.com/JiangXia-1024?tab=repositories
本文一共1278字,预计阅读12分钟
1、介绍
@Transactional 是 Spring 框架中的一个注解,用于标识某个方法或类需要进行事务管理。它的原理是基于 AOP(面向切面编程)和代理模式。
当使用 @Transactional 注解时,Spring 会通过动态代理的方式为被注解的方法生成一个代理对象。这个代理对象会拦截方法的调用,在方法执行前后开启和提交事务。具体原理如下:
1. 在方法调用前,代理对象会开启一个新的事务。如果已经存在一个事务,则会加入该事务中。
2. 方法执行过程中,如果发生异常,则事务会被回滚,即撤销已经执行的操作。
3. 方法执行完成后,代理对象会提交事务。如果事务执行过程中发生异常,事务会被回滚。
@Transactional 注解还有一些属性可以设置,例如 isolation(事务隔离级别)、propagation(事务传播行为)、timeout(事务超时时间)等,可以根据具体需求进行配置。
2、代码
下面是一个简单的代码演示,展示了如何使用 @Transactional 注解进行事务管理:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(User user) {
userRepository.save(user);
}
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void updateUser(User user) {
userRepository.save(user);
if (user.getId() == null) {
throw new IllegalArgumentException("User ID cannot be null");
}
}
@Transactional(propagation = Propagation.REQUIRED, timeout = 10)
public void deleteUser(Long userId) {
userRepository.deleteById(userId);
}
}
在上面的示例中,UserService 类中的三个方法都使用了 @Transactional 注解。
- createUser 方法使用了默认的事务传播行为和超时时间,即默认情况下会开启一个新的事务,并且没有设置超时时间。
- updateUser 方法设置了事务传播行为为 REQUIRED(如果当前存在事务,则加入该事务),并且设置了回滚策略为 Exception.class,即遇到任何异常都会触发事务回滚。
- deleteUser 方法设置了事务传播行为为 REQUIRED,超时时间为 10 秒,即如果方法执行时间超过 10 秒,事务会自动回滚。
需要注意的是,在 UserService 类中的方法之间进行调用时,@Transactional 注解可能不会生效。如果想要在调用方法内部也生效,可以将方法抽取到另一个类中,或者使用 self-invocation(通过 this 调用方法)。
希望以上示例能够帮助你理解 @Transactional 注解的使用和原理。
使用 @Transactional 注解时需要注意一些坑:
1. 注解的类或方法必须是 public 的,因为 Spring 使用动态代理来生成代理对象,只能代理公共方法。
2. 默认情况下,只有抛出 RuntimeException 及其子类的异常才会触发事务回滚。如果要让其他异常也触发事务回滚,可以使用 @Transactional(rollbackFor = Exception.class) 来设置。
3. 在同一个类中的方法调用,@Transactional 注解可能不起作用。这是因为 Spring 使用的是基于代理的 AOP,默认只能拦截从外部调用的方法。可以通过将方法抽取到另一个类中,或者使用 self-invocation(通过 this 调用方法)来解决这个问题。
4. @Transactional 注解应该被应用到 public 方法上,而不是 private 或 protected 方法上。因为 Spring 使用的是基于代理的 AOP,只能拦截公共方法。
4、总结
总之,@Transactional 注解可以方便地实现事务管理,但在使用时需要注意一些细节,避免出现意外的问题。
最后感谢大家的关注!
-END-