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

深入解析Spring Boot中的`@Transactional`注解

一、@Transactional注解概述

1.1 什么是@Transactional

@Transactional是Spring框架中用于声明式事务管理的注解。通过在方法或类上添加@Transactional注解,Spring会自动将该方法或类中的数据库操作纳入到事务管理中,从而保证这些操作的原子性、一致性、隔离性和持久性(即ACID属性)。

1.2 @Transactional的作用

@Transactional的主要作用是管理数据库事务,它可以确保:

  • 原子性:方法中的多个数据库操作要么全部成功,要么全部失败。
  • 一致性:事务执行前后,数据库保持一致性。
  • 隔离性:事务之间相互隔离,防止并发问题。
  • 持久性:事务一旦提交,结果将永久保存到数据库中。

二、@Transactional的工作原理

2.1 基于AOP的事务管理

Spring的事务管理是基于AOP(面向切面编程)实现的。当一个方法被@Transactional注解标记时,Spring会为该方法生成一个代理对象,代理对象会在方法执行前开启事务,在方法执行完成后提交事务,如果方法抛出异常,则回滚事务。

2.2 事务传播机制

@Transactional注解中的propagation属性决定了当前事务的传播行为。Spring支持以下几种传播行为:

  • REQUIRED(默认值):如果当前存在事务,则加入该事务;如果当前没有事务,则新建一个事务。
  • REQUIRES_NEW:每次都会新建一个事务,如果当前存在事务,则挂起当前事务。
  • SUPPORTS:支持当前事务,如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
  • NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起当前事务。
  • MANDATORY:必须在一个已有事务中执行,如果当前没有事务,则抛出异常。
  • NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  • NESTED:如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则新建一个事务。

2.3 事务隔离级别

@Transactional注解中的isolation属性决定了事务的隔离级别。Spring支持以下几种隔离级别:

  • DEFAULT:使用底层数据库的默认隔离级别。
  • READ_UNCOMMITTED:最低的隔离级别,可能导致脏读、不可重复读和幻读。
  • READ_COMMITTED:可以防止脏读,但仍可能出现不可重复读和幻读。
  • REPEATABLE_READ:可以防止脏读和不可重复读,但仍可能出现幻读。
  • SERIALIZABLE:最高的隔离级别,确保事务的完整性,但性能较低。

2.4 事务超时与只读设置

  • timeout属性:指定事务的超时时间,单位为秒。如果事务在指定时间内没有完成,则会回滚。
  • readOnly属性:设置事务为只读,优化数据库操作,特别是在查询操作时。

2.5 事务回滚策略

  • rollbackFor属性:指定哪些异常会导致事务回滚。默认情况下,Spring会在遇到RuntimeExceptionError时回滚事务。
  • noRollbackFor属性:指定哪些异常不会导致事务回滚。

三、@Transactional注解的实际应用

3.1 方法级别的事务管理

通常情况下,我们会在服务层(Service Layer)的方法上使用@Transactional注解,以确保这些方法中的数据库操作能够被事务管理。

@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Transactionalpublic void createUser(User user) {userRepository.save(user);// 其他业务逻辑}
}

在上述例子中,createUser方法被@Transactional注解标记,这意味着在该方法执行期间,如果出现异常,所有数据库操作都会被回滚。

3.2 类级别的事务管理

@Transactional注解也可以放在类级别,这样类中所有的public方法都会被事务管理。

@Service
@Transactional
public class UserService {@Autowiredprivate UserRepository userRepository;public void createUser(User user) {userRepository.save(user);// 其他业务逻辑}public void deleteUser(Long id) {userRepository.deleteById(id);// 其他业务逻辑}
}

在此例子中,UserService类中所有的public方法都会被事务管理。

3.3 多事务管理器

在复杂的应用中,可能会有多个数据源,此时我们需要配置多个事务管理器,并在@Transactional注解中指定使用哪个事务管理器。

@Configuration
@EnableTransactionManagement
public class DataSourceConfig {@Bean(name = "firstTransactionManager")public PlatformTransactionManager firstTransactionManager(EntityManagerFactoryBuilder builder) {return new JpaTransactionManager(firstEntityManagerFactory(builder).getObject());}@Bean(name = "secondTransactionManager")public PlatformTransactionManager secondTransactionManager(EntityManagerFactoryBuilder builder) {return new JpaTransactionManager(secondEntityManagerFactory(builder).getObject());}
}

在Service层中,可以通过@Transactional注解的transactionManager属性指定使用哪个事务管理器:

@Service
public class OrderService {@Autowiredprivate OrderRepository orderRepository;@Transactional(transactionManager = "firstTransactionManager")public void processOrder(Order order) {orderRepository.save(order);// 其他业务逻辑}
}

3.4 嵌套事务

在某些情况下,我们可能需要在一个事务中嵌套另一个事务。Spring提供了NESTED事务传播行为,支持这种需求。

@Service
public class OrderService {@Autowiredprivate PaymentService paymentService;@Transactionalpublic void processOrder(Order order) {paymentService.processPayment(order);// 其他业务逻辑}
}@Service
public class PaymentService {@Transactional(propagation = Propagation.NESTED)public void processPayment(Order order) {// 支付逻辑}
}

在上述例子中,PaymentService中的processPayment方法被NESTED传播行为标记,这意味着即使processOrder方法回滚,processPayment方法的操作也可以单独回滚或提交。

四、@Transactional注解的常见问题与解决方案

4.1 @Transactional注解不生效

原因分析
  • 方法可见性问题@Transactional注解只会在public方法上生效,如果方法是private、protected或者package-private,则事务不会被代理。
  • 自调用问题:当同一个类中的方法相互调用时,如果调用者和被调用者都使用了@Transactional,Spring不会代理这种情况,导致事务不生效。
  • 配置问题:检查@EnableTransactionManagement注解是否正确配置,确保事务管理器被正确加载。
解决方案
  • 确保使用@Transactional注解的方法是public的。
  • 使用AOP配置或者将方法调用移到外部类中,以避免自调用导致的问题。
  • 确保在配置类中正确启用了事务管理。

4.2 嵌套事务回滚问题

原因分析

嵌套事务的回滚机制较为复杂,默认情况下,嵌套事务的回滚可能不会影响到外部事务,导致数据不一致。

解决方案

可以通过Propagation.NESTEDPropagation.REQUIRES_NEW来区分不同的事务边界,从而确保在出现问题时回滚到预期的事务状态。

4.3 事务隔离级别导致的性能问题

原因分析

高隔离级别(如SERIALIZABLE)会显著降低数据库的并发性能,导致系统吞吐量下降。

解决方案

在实际应用中,应该根据业务需求选择合适的事务隔离级别,避免不必要的高隔离级别配置。同时,优化数据库索引和查询策略,减少锁冲突。

五、总结

@Transactional是Spring Boot中一个非常强大的注解,它简化了事务管理

,使得开发者可以专注于业务逻辑的实现。然而,在实际应用中,合理地使用@Transactional注解并避免常见的坑,仍然是一个需要深入理解和持续实践的过程。希望本文能够帮助你更好地掌握@Transactional注解的使用,并在项目中发挥其最大价值。


通过理解Spring Boot中的@Transactional注解,你可以更好地掌握事务管理的原理,并在实际开发中应用这些知识来编写健壮的、易维护的代码。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 数据结构--带头双向循环链表
  • Gitlab-ce upgrade 16.0.1 to 17.3.1【Gitlab-ce 16.0.1 升级 17.3.1】
  • 828华为云征文|基于华为云Flexus云服务器X搭建FTP服务器
  • 集成电路学习:什么是IDE集成开发环境
  • 量化交易面试:什么是资本资产定价模型?
  • 新兴专业网络安全专业就业前景怎么样?有哪些就业去向?零基础入门到精通,收藏这一篇就够了
  • 子网ip和ip地址一样吗?子网ip地址怎么算
  • 每日工作总结(1)2024-0902
  • IDEA 安装lombok插件不兼容的问题及解决方法
  • c++开源库安装
  • 什么样的数据安全交换系统 能构建坚不可摧的跨网传输堡垒?
  • Python(TensorFlow)和MATLAB及Java光学像差导图
  • 6 - Shell编程之sed与awk编辑器
  • Spring6梳理6——依赖注入之Setter注入
  • Python-FLASK上传文件
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • Cumulo 的 ClojureScript 模块已经成型
  • isset在php5.6-和php7.0+的一些差异
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • leetcode46 Permutation 排列组合
  • node-glob通配符
  • Vue小说阅读器(仿追书神器)
  • Vue组件定义
  • Yii源码解读-服务定位器(Service Locator)
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 官方新出的 Kotlin 扩展库 KTX,到底帮你干了什么?
  • 两列自适应布局方案整理
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 区块链共识机制优缺点对比都是什么
  • 如何设计一个比特币钱包服务
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 突破自己的技术思维
  • 写代码的正确姿势
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • Spring Batch JSON 支持
  • #mysql 8.0 踩坑日记
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • (11)MSP430F5529 定时器B
  • (第30天)二叉树阶段总结
  • (附源码)springboot优课在线教学系统 毕业设计 081251
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (力扣)循环队列的实现与详解(C语言)
  • (四)JPA - JQPL 实现增删改查
  • (一一四)第九章编程练习
  • (转)甲方乙方——赵民谈找工作
  • .[backups@airmail.cc].faust勒索病毒的最新威胁:如何恢复您的数据?
  • .NET 8.0 中有哪些新的变化?
  • .net 程序 换成 java,NET程序员如何转行为J2EE之java基础上(9)
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • [Angular] 笔记 18:Angular Router