@Transactional

本文详细介绍了Spring框架中的@Transactional注解,包括其在接口实现类和方法上的使用位置,以及对public方法的要求。同时,指出了错误使用的情况,如在非public方法上使用,事务不生效的间接调用,以及异常处理与事务回滚的关系。此外,还提到了多线程环境下@Transactional注解的限制,强调了事务管理与多线程操作的注意事项。

@Transactional 是声明式事务管理 编程中使用的注解

1 .添加位置

1)接口实现类或接口实现方法上,而不是接口类中。
2)访问权限:public 的方法才起作用。@Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。
系统设计:将标签放置在需要进行事务管理的方法上,而不是放在所有接口实现类上:只读的接口就不需要事务管理,由于配置了@Transactional就需要AOP拦截及事务的处理,可能影响系统性能。

//原生SQL添加一个新用户
    @Modifying //update delete操作注释
    @Transactional //声明式事务管理注释 ,事务只读不需要该注释
    @Query(value="insert into User(name,password) values(?1,?2)",nativeQuery=true)
    public void savaNewUser(String name,String password);

3)错误使用:

1.接口中A、B两个方法,A无@Transactional标签,B有,上层通过A间接调用B,此时事务不生效。
 
2.接口中异常(运行时异常)被捕获而没有被抛出。
  默认配置下,spring 只有在抛出的异常为运行时 unchecked 异常时才回滚该事务,
  也就是抛出的异常为RuntimeException 的子类(Errors也会导致事务回滚),
  而抛出 checked 异常则不会导致事务回滚 。可通过 @Transactional rollbackFor进行配置。
 
3.多线程下事务管理因为线程不属于 spring 托管,故线程不能够默认使用 spring 的事务,
  也不能获取spring 注入的 bean 。
  在被 spring 声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制。
  一个使用了@Transactional 的方法,如果方法内包含多线程的使用,方法内部出现异常,
  不会回滚线程中调用方法的事务。
 

<think> 嗯,用户想了解Spring框架中@Transactional注解的使用、原理和应用。根据之前的对话历史,用户已经看到了一些参考资料,包括事务的位置选择、代理机制实现和源码层面的实现位置。不过用户希望获得更系统的解释,可能是个正在学习Spring事务管理的开发者。 用户提到“可能包括使用方法、原理、在框架中的应用等”,说明需要分层解答。先从最直观的使用方法入手比较合理,这样用户能快速上手实践。原理部分需要解释清楚AOP代理机制,这点引用[2]提到了代理对象创建,引用[3]提到TransactionAspectSupport的源码位置,可以结合起来说明。应用场景方面用户可能关心实际开发中的注意事项。 注意到引用[1]特别强调不要在接口上使用@Transactional的细节,这个坑点必须重点提示。另外用户提供的引用中有多处细节互相补充:比如方法级注解会覆盖类级注解(引用[1])、事务传播行为参数(引用[2]补充)、实际事务创建位置(引用[3]的createTransactionIfNecessary方法),这些都需要有机整合到回答中。 安全方面要提醒事务超时和回滚规则设定,特别是服务层事务的耗时控制。性能方面注意读操作不需要事务,避免资源浪费。用户可能遇到的常见坑点比如自调用失效问题,需要给出具体解决方案——用AopContext.currentProxy()或者注入自身Bean的方法。 最后考虑设计几个衍生问题:事务传播行为的具体案例(比如嵌套事务场景)、分布式事务的整合方案、隔离级别的选择依据等。这些既延续当前话题深度,又覆盖用户可能的后续疑问。 </think> 好的,我们来系统梳理一下 Spring 框架中 `@Transactional` 注解的使用方法、实现原理以及在框架中的应用。 ## 一、@Transactional 注解的使用方法 `@Transactional` 注解主要用于声明式事务管理,其核心目的是简化事务代码,让开发者专注于业务逻辑。主要使用方式和配置项如下: 1. **注解位置**: * **类级别**:放置在类声明上方。作用是该类中所有的 `public` 方法都将具有该注解定义的事务属性。这是最常见的用法。 * **方法级别**:放置在具体的 `public` 方法上方(对 `private`, `protected`, `package-visible` 方法无效)。作用范围仅限于该方法。**方法级别的事务属性定义会覆盖类级别的定义**。 * **接口级别(不推荐)**:Spring 官方**强烈建议**不要将 `@Transactional` 标注在接口或接口方法上。因为它仅在 Spring 使用基于接口的代理(如 JDK 动态代理)时才生效。如果使用了基于类的代理(如 CGLIB)或者采用基于 AspectJ 的织入方式,接口上的注解会被忽略,导致事务失效[^1]。 2. **关键配置属性**: * `propagation`: 定义事务的**传播行为**(默认 `Propagation.REQUIRED`)。决定当前方法在调用时,如何处理现有事务(新开事务、加入现有事务、非事务执行等)。常见值: * `REQUIRED`:如果当前存在事务,则加入该事务;如果不存在,则创建一个新事务。 * `REQUIRES_NEW`:总是新建一个事务,如果当前存在事务,则挂起它。 * `SUPPORTS`:如果当前存在事务,则加入;否则以非事务方式执行。 * `NOT_SUPPORTED`:以非事务方式执行,如果当前存在事务,则挂起它。 * `MANDATORY`:必须在事务中运行,否则抛出异常。 * `NEVER`:必须在非事务中运行,否则抛出异常。 * `NESTED`:如果当前存在事务,则在嵌套事务内执行(使用保存点)。 * `isolation`: 定义事务的**隔离级别**(默认 `Isolation.DEFAULT`,通常对应数据库默认级别)。解决并发事务可能引发的脏读、不可重复读、幻读问题。常见值: * `DEFAULT`: 使用底层数据库默认隔离级别。 * `READ_UNCOMMITTED` * `READ_COMMITTED` * `REPEATABLE_READ` * `SERIALIZABLE` * `timeout`: 定义事务的**超时时间**(以秒为单位,默认 -1,表示使用底层系统默认超时)。超过该时间未完成,事务将自动回滚。 * `readOnly`: 指示事务是否为**只读事务**(默认 `false`)。设为 `true` 可以优化某些操作(如 Hibernate 的 flush 模式)。 * `rollbackFor` / `rollbackForClassName`: 指定哪些**异常类型**(或其子类)会导致事务回滚(默认只在抛出 `RuntimeException` 和 `Error` 时回滚)。你可以指定具体的异常类或其类名。 * `noRollbackFor` / `noRollbackForClassName`: 指定哪些异常类型(或其子类)**即使抛出也不导致**事务回滚。 3. **基本使用示例**: ```java @Service public class OrderService { @Autowired private OrderRepository orderRepository; @Autowired private PaymentService paymentService; // 类级别的注解作为默认,方法级别的覆盖特定行为 @Transactional(readOnly = true, timeout = 30) public Order findOrderById(Long id) { return orderRepository.findById(id).orElse(null); } // 使用 REQUIRES_NEW 传播行为,确保支付操作独立提交 @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = PaymentException.class) public void processPayment(Order order, PaymentInfo paymentInfo) throws PaymentException { // ... 支付处理逻辑,可能抛出 PaymentException } // 默认 REQUIRED 传播,创建订单和支付在同一个事务中 @Transactional // 使用类默认的传播行为(REQUIRED)和隔离级别等 public Order createOrder(OrderDetails details, PaymentInfo paymentInfo) throws PaymentException { Order newOrder = orderRepository.save(createNewOrder(details)); processPayment(newOrder, paymentInfo); // 调用 REQUIRES_NEW 方法会挂起当前事务,新开事务 // ... 其他操作 return newOrder; // 如果 processPayment 成功,但此处出错,createOrder 事务会回滚,但 processPayment 事务已提交 } } ``` ## 二、@Transactional 注解的实现原理 `@Transactional` 的核心原理是 Spring 的 **AOP(面向切面编程)** 机制,具体实现依赖于 **代理模式(Proxy Pattern)**: 1. **代理对象的创建**: * 当 Spring 容器启动时,会扫描所有被 `@Component`、`@Service`、`@Repository` 等注解标记的 Bean。 * 对于包含 `@Transactional` 注解的类(或其方法)的 Bean,Spring 事务管理基础设施会识别它们。 * Spring **动态地为这些 Bean 创建代理对象**(Proxy Object)。这个代理对象包裹了原始的目标对象(Target Object)[^2]。代理的创建方式有两种: * **JDK 动态代理**:如果目标类实现了至少一个接口,则生成一个实现了相同接口的代理类。 * **CGLIB 字节码增强**:如果目标类没有实现任何接口,则直接生成目标类的子类作为代理类。 2. **拦截器链与事务拦截器**: * 代理对象内部维护了一个**拦截器链(Interceptor Chain)**。当一个带有 `@Transactional` 的方法被外部调用时,实际上调用的是代理对象上的方法。 * 代理对象会检查被调用的方法是否需要事务管理(即是否被 `@Transactional` 注解或其类被注解且方法是 `public`)。 * 如果需要事务管理,代理对象会将方法调用**委托给一个特殊的拦截器**:`TransactionInterceptor`。 3. **事务控制的核心 - TransactionInterceptor**: * `TransactionInterceptor` 是事务处理的核心逻辑所在。它的 `invoke()` 方法负责整个事务的生命周期管理。 * 在目标方法被调用**之前**: * 拦截器通过 `PlatformTransactionManager`(事务管理器,如 `DataSourceTransactionManager`, `HibernateTransactionManager`, `JtaTransactionManager`)**根据`@Transactional`属性创建一个新的事务或加入一个现有事务**。 * 这通常涉及到从 `TransactionManager` 获取一个 `TransactionStatus` 对象来表示当前事务的状态。 * 对应源码的关键入口点如 `TransactionAspectSupport.invokeWithinTransaction()` -> `createTransactionIfNecessary()`[^3]. * 在目标方法被调用**期间**: * 执行目标方法的业务逻辑。 * 在目标方法**执行完成后**(正常返回或抛出异常): * **正常返回**:拦截器根据事务定义决定是否提交事务(对于 `REQUIRED`,通常在方法最外层提交)。提交操作调用 `commit()`。 * **抛出异常**:拦截器捕获异常,检查该异常类型是否满足 `@Transactional(rollbackFor=...)` 或 `@Transactional(noRollbackFor=...)` 的规则。如果异常类型指示需要回滚(默认 `RuntimeException` / `Error`),则调用 `rollback()` 回滚事务。否则,也可能提交事务(但很少见)。 4. **PlatformTransactionManager 的作用**: * 这是 Spring 事务抽象的核心接口 (`DataSourceTransactionManager`, `HibernateTransactionManager` 等是其实现)。它屏蔽了底层具体事务资源(JDBC, JPA, JTA)的差异。 * `TransactionInterceptor` 通过调用 `PlatformTransactionManager` 的 `getTransaction()`, `commit()`, `rollback()` 等方法来具体操作事务。 **流程图简化表示**: ``` [外部调用者] --> [代理对象] --> TransactionInterceptor.invoke() | V createTransactionIfNecessary() [^3] --> 获取/创建事务 (PlatformTransactionManager) | V try { [反射调用目标方法] --> 执行业务逻辑 commitIfNecessary() } catch(Throwable ex) { completeTransactionAfterThrowing() --> 检查异常是否需要回滚 if (需要回滚) rollback() else commit() rethrow ex } ``` ## 三、@TransactionalSpring 框架中的应用 1. **声明式事务管理**: * 这是 `@Transactional` 最主要、最核心的应用场景。 * 开发者只需通过简单的注解配置事务属性(传播、隔离、超时、只读、回滚规则),无需手动编写繁琐的 `try-catch-finally` 块来管理 `Connection` 的获取、提交、回滚和释放。Spring 框架自动处理这些事务边界代码。 * **显著优点**:大大减少了样板代码,提高了开发效率和代码可读性;事务管理与业务逻辑解耦,更符合单一职责原则;配置灵活,易于维护和更改。 2. **管理多种持久化技术的事务**: * 通过配置不同的 `PlatformTransactionManager` 实现,`@Transactional` 可以统一管理不同持久层技术的事务: * **JDBC / Spring JdbcTemplate**:使用 `DataSourceTransactionManager`。 * **JPA (Hibernate)**:使用 `JpaTransactionManager`。 * **Hibernate (原生)**:使用 `HibernateTransactionManager`。 * **JTA (分布式事务)**:使用 `JtaTransactionManager`。 * 应用代码中的 `@Transactional` 用法保持一致,只需切换底层的事务管理器即可。 3. **集成测试**: * 在 Spring TestContext Framework 中,`@Transactional` 注解常用于测试方法上。 * 默认情况下,在测试方法结束时,Spring 会自动回滚测试期间对数据库所做的修改,确保测试之间数据的隔离性,避免测试污染。这对于编写可重复执行的 DAO/Repository 层或 Service 层集成测试非常有用。 * 可以通过 `@Rollback(false)` 禁用自动回滚。 ## 四、重要注意事项与常见陷阱 1. **事务方法的可见性**:`@Transactional` 只对 `public` 方法有效。`private`, `protected`, `package-visible` 方法上的注解会被忽略(因为代理对象无法覆盖调用这些方法)。 2. **自调用失效**:在同一个 Bean 内部,一个非事务方法 `A()` 调用同一个 Bean 中的事务方法 `B()`,会导致 `B()` 的事务失效。因为 `A()` 调用 `B()` 时,是通过 `this.B()` 进行的(即目标对象本身,而不是代理对象),绕过了代理和拦截器。解决方法: * 将 `A()` 和 `B()` 拆分到不同的 Bean 中。 * 使用 `AopContext.currentProxy()` 获取当前代理对象,然后调用 `((YourServiceClass) AopContext.currentProxy()).B()`(需要暴露代理 `@EnableAspectJAutoProxy(exposeProxy = true)`)。 * 通过注入自身 Bean 来完成内部调用(不推荐,易循环依赖)。 3. **异常回滚规则**: * 默认只回滚 `RuntimeException` 和 `Error`。**受检异常(Checked Exception,如 `SQLException`, `IOException`)默认不回滚**!务必使用 `rollbackFor` 或 `rollbackForClassName` 明确指定需要回滚的受检异常类型。 * 使用 `noRollbackFor` 指定即使抛出某些 `RuntimeException` 也不回滚。 4. **事务传播行为理解**:务必清晰理解不同传播行为(尤其是 `REQUIRED`, `REQUIRES_NEW`, `NESTED`)的含义和适用场景,否则可能导致事务边界混乱或死锁。 5. **只读事务优化**:对于只进行查询操作的方法,明确设置 `readOnly = true`。这能给底层持久化框架(如 Hibernate)提供优化提示(例如关闭脏检查、flush)。 6. **正确选择事务管理器**:确保配置的事务管理器与使用的持久化技术(JDBC, JPA, Hibernate)匹配。 ## 总结 Spring 的 `@Transactional` 注解是实现声明式事务管理的核心工具。它通过 AOP 和代理机制,在运行时动态地为标注的方法或类添加事务管理逻辑。开发者只需通过简单的注解配置事务属性(传播、隔离、超时、只读、回滚规则),即可享受到事务的 ACID 特性,而无需编写繁琐的事务管理代码。理解其工作原理(代理、拦截器、事务管理器)对于正确使用和排查事务相关问题至关重要,同时要特别注意可见性、自调用、异常处理和传播行为等常见陷阱。它广泛应用于简化业务层的事务管理,支持多种持久化技术,并在集成测试中发挥重要作用。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值