当前位置: 首页 > news >正文

深入理解 @Transactional 注解在 Spring 中的应用

        前言:在 Java 开发中,事务管理是非常重要的一环。Spring 框架提供了@Transactional注解来简化事务管理的操作,本文将深入介绍@Transactional注解的用法,并结合代码示例进行详细讨论。

1.@Transactional 注解简介

    @Transactional注解是 Spring 框架中用于管理事务的关键注解之一。通过在方法或类上添加该注解,Spring 会自动为被注解的方法创建一个事务,并在方法执行完毕后根据执行情况提交或回滚事务。这样可以确保数据库操作的原子性,保证数据的完整性。

@Service
@Transactional
public class UserService {@Autowiredprivate UserRepository userRepository;public void updateUser(User user) {userRepository.save(user);}
}

在上面的示例中,@Transactional注解被添加到UserService类上,表示其中的方法将在事务管理下执行。

2.@Transactional 失效的情况

        尽管@Transactional注解可以很好地管理事务,但在某些情况下它可能会失效,导致事务无法正常工作。以下是一些可能导致@Transactional注解失效的情况:

2.1 自调用问题 

        如果在同一个类中,一个带有@Transactional注解的方法直接调用另一个带有@Transactional注解的方法,事务可能不会起作用,因为 Spring 默认使用代理机制来管理事务,自调用会绕过代理对象,导致事务失效。

@Service
@Transactional
public class UserService {@Autowiredprivate UserRepository userRepository;public void updateUser(User user) {saveUser(user); // 这里的调用会绕过代理对象,事务失效}@Transactionalpublic void saveUser(User user) {userRepository.save(user);}
}

2.2 异常捕获问题

        当方法内部捕获了异常并不再抛出时,事务可能会失效。Spring 默认只会对未捕获的异常进行事务回滚,如果异常被捕获并在方法内部处理,事务可能无法正常回滚。

@Service
@Transactional
public class UserService {@Autowiredprivate UserRepository userRepository;public void updateUser(User user) {try {userRepository.save(user);} catch (Exception e) {// 异常被捕获,事务可能无法回滚}}
}

2.3 抛出非运行时异常

        异常虽然抛出了,但是抛出的是非RuntimeException类型的异常,依旧不会生效。

@Transactional
public void deleteUser() throws MyException{userMapper.deleteUserA();try {int i = 1 / 0;userMapper.deleteUserB();} catch (Exception e) {throw new MyException();}
}

        如果指定了回滚异常类型为Exception,那么就可以回滚非RuntimeException类型异常了。

@Transactional(rollbackFor = Exception.class)

2.4 新开启一个线程

        如下的方式deleteUserA()也不会回滚,因为spring实现事务的原理是通过ThreadLocal把数据库连接绑定到当前线程中,新开启一个线程获取到的连接就不是同一个了:

@Transactional
public void deleteUser() throws MyException{userMapper.deleteUserA();try {//休眠1秒,保证deleteUserA先执行Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {int i = 1/0;userMapper.deleteUserB();}).start();    
}

2.5 非public方法

        如果@Transactional注解标记的方法是非public的,那么事务将失效。这是因为Spring默认使用基于代理的AOP来实现事务,而基于代理的AOP只能拦截public方法。

@Transactional
private void doSomething() {// 执行业务逻辑
}

2.6 未被Spring容器管理

        如果@Transactional注解标记的方法所在的类没有被Spring容器管理,那么事务将失效。这是因为Spring只会对由Spring容器管理的Bean进行事务管理。


public class UserService {@Autowiredprivate UserRepository userRepository;@Transactionalpublic void updateUser(User user) {userRepository.save(user);}
}

2.7 数据库本身不支持

        数据库本身不支持事务管理。mysql数据库,必须设置数据库引擎为InnoDB。

2.8 事务传播属性设置错误

        注意传播属性的设置,比如设置了:PROPAGATION_NOT_SUPPORIED(以非事务的方式执行,如果当前有事务则把当前事务挂起)。

3. 解决方案

        针对上述问题,我们可以采取一些解决方案来确保@Transactional注解的有效性。比如避免在同一个类中使用自调用的方式,或者在捕获异常后手动抛出以触发事务回滚。

4. 总结

        通过@Transactional注解,我们可以轻松管理事务,确保数据库操作的一致性。然而,在编写代码时需要注意可能导致注解失效的情况,避免出现意外的事务行为。持续学习和实践是掌握事务管理的关键,希望本文对您有所帮助。

http://www.lryc.cn/news/326720.html

相关文章:

  • Python爬虫之爬取网页图片
  • AI Agent(LLM Agent)入门解读
  • 自动化面试常见算法题!
  • CCF-CSP真题202206-2《寻宝!大冒险!》
  • Rust编程(三)生命周期与异常处理
  • 【办公类-21-11】 20240327三级育婴师 多个二级文件夹的docx合并成docx有页码,转PDF
  • OSG编程指南<二十一>:OSG视图与相机视点更新设置及OSG宽屏变形
  • Laplace变换-3
  • LVS负载均衡-DR模式配置
  • 【unity】如何汉化unity Hub
  • 【算法】KMP-快速文本匹配
  • 多维数组和交错数组笔记
  • Python(django)之单一接口展示功能前端开发
  • 【大模型】非常好用的大语言模型推理框架 bigdl-llm,现改名为 ipex-llm
  • Kubernetes示例yaml:3. service-statefulset.yaml
  • Windows平台cmake编译QT源码库,使用VScode开发QT
  • 腾讯云轻量8核16G18M服务器多少钱一年?
  • 二分练习题——123
  • 淘宝详情数据采集(商品上货,数据分析,属性详情,价格监控),海量数据值得get
  • Django之Web应用架构模式
  • GPT提示词分享 —— 口播脚本
  • 笔记本作为其他主机显示屏(HDMI采集器)
  • 02.percona Toolkit工具pt-archiver命令实践
  • 【天狼启航者】研究计划
  • 面试题 之 webpack
  • 【机器学习之旅】概念启程、步骤前行、分类掌握与实践落地
  • 外星人m18R2国行中文版原厂预装23H2原装Win11系统恢复带F12恢复重置
  • libVLC 视频抓图
  • Docker搭建LNMP环境实战(06):Docker及Docker-compose常用命令
  • ClickHouse10-ClickHouse中Kafka表引擎