Spring中@Transactional用法深度分析之一

深入理解Spring @Transactional
本文详细解析了Spring框架中@Transactional注解的各个属性及其应用场景,包括value、propagation等,并通过示例介绍了如何在Spring配置文件中启用@Transactional进行事务管理。

引言: 在spring中@Transactional提供一种控制事务管理的快捷手段,但是很多人都只是@Transactional简单使用,并未深入了解,其各个配置项的使用方法,本文将深入讲解各个配置项的使用。

1.  @Transactional的定义

    Spring中的@Transactional基于动态代理的机制,提供了一种透明的事务管理机制,方便快捷解决在开发中碰到的问题。在现实中,实际的问题往往比我们预期的要复杂很多,这就要求对@Transactional有深入的了解,以来应对复杂问题。

   首先我们来看看@Transactional的代码定义:

  1. @Target({ElementType.METHOD, ElementType.TYPE})  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. @Inherited  
  4. @Documented  
  5. public @interface Transactional {  
  6.   
  7.     /**  
  8.      * A qualifier value for the specified transaction.  
  9.      * <p>May be used to determine the target transaction manager,  
  10.      * matching the qualifier value (or the bean name) of a specific  
  11.      * {@link org.springframework.transaction.PlatformTransactionManager}  
  12.      * bean definition.  
  13.      */  
  14.     String value() default "";  
  15.   
  16.     /**  
  17.      * The transaction propagation type.  
  18.      * Defaults to {@link Propagation#REQUIRED}.  
  19.      * @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior()  
  20.      */  
  21.     Propagation propagation() default Propagation.REQUIRED;  
  22.   
  23.     /**  
  24.      * The transaction isolation level.  
  25.      * Defaults to {@link Isolation#DEFAULT}.  
  26.      * @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel()  
  27.      */  
  28.     Isolation isolation() default Isolation.DEFAULT;  
  29.   
  30.     /**  
  31.      * The timeout for this transaction.  
  32.      * Defaults to the default timeout of the underlying transaction system.  
  33.      * @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()  
  34.      */  
  35.     int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;  
  36.   
  37.     /**  
  38.      * {@code true} if the transaction is read-only.  
  39.      * Defaults to {@code false}.  
  40.      * <p>This just serves as a hint for the actual transaction subsystem;  
  41.      * it will <i>not necessarily</i> cause failure of write access attempts.  
  42.      * A transaction manager which cannot interpret the read-only hint will  
  43.      * <i>not</i> throw an exception when asked for a read-only transaction.  
  44.      * @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()  
  45.      */  
  46.     boolean readOnly() default false;  
  47.   
  48.     /**  
  49.      * Defines zero (0) or more exception {@link Class classes}, which must be a  
  50.      * subclass of {@link Throwable}, indicating which exception types must cause  
  51.      * a transaction rollback.  
  52.      * <p>This is the preferred way to construct a rollback rule, matching the  
  53.      * exception class and subclasses.  
  54.      * <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)}  
  55.      */  
  56.     Class<? extends Throwable>[] rollbackFor() default {};  
  57.   
  58.     /**  
  59.      * Defines zero (0) or more exception names (for exceptions which must be a  
  60.      * subclass of {@link Throwable}), indicating which exception types must cause  
  61.      * a transaction rollback.  
  62.      * <p>This can be a substring, with no wildcard support at present.  
  63.      * A value of "ServletException" would match  
  64.      * {@link javax.servlet.ServletException} and subclasses, for example.  
  65.      * <p><b>NB: </b>Consider carefully how specific the pattern is, and whether  
  66.      * to include package information (which isn't mandatory). For example,  
  67.      * "Exception" will match nearly anything, and will probably hide other rules.  
  68.      * "java.lang.Exception" would be correct if "Exception" was meant to define  
  69.      * a rule for all checked exceptions. With more unusual {@link Exception}  
  70.      * names such as "BaseBusinessException" there is no need to use a FQN.  
  71.      * <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)}  
  72.      */  
  73.     String[] rollbackForClassName() default {};  
  74.   
  75.     /**  
  76.      * Defines zero (0) or more exception {@link Class Classes}, which must be a  
  77.      * subclass of {@link Throwable}, indicating which exception types must <b>not</b>  
  78.      * cause a transaction rollback.  
  79.      * <p>This is the preferred way to construct a rollback rule, matching the  
  80.      * exception class and subclasses.  
  81.      * <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)}  
  82.      */  
  83.     Class<? extends Throwable>[] noRollbackFor() default {};  
  84.   
  85.     /**  
  86.      * Defines zero (0) or more exception names (for exceptions which must be a  
  87.      * subclass of {@link Throwable}) indicating which exception types must <b>not</b>  
  88.      * cause a transaction rollback.  
  89.      * <p>See the description of {@link #rollbackForClassName()} for more info on how  
  90.      * the specified names are treated.  
  91.      * <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)}  
  92.      */  
  93.     String[] noRollbackForClassName() default {};  
  94.   
  95. }  
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

	/**
	 * A qualifier value for the specified transaction.
	 * <p>May be used to determine the target transaction manager,
	 * matching the qualifier value (or the bean name) of a specific
	 * {@link org.springframework.transaction.PlatformTransactionManager}
	 * bean definition.
	 */
	String value() default "";

	/**
	 * The transaction propagation type.
	 * Defaults to {@link Propagation#REQUIRED}.
	 * @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior()
	 */
	Propagation propagation() default Propagation.REQUIRED;

	/**
	 * The transaction isolation level.
	 * Defaults to {@link Isolation#DEFAULT}.
	 * @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel()
	 */
	Isolation isolation() default Isolation.DEFAULT;

	/**
	 * The timeout for this transaction.
	 * Defaults to the default timeout of the underlying transaction system.
	 * @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()
	 */
	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

	/**
	 * {@code true} if the transaction is read-only.
	 * Defaults to {@code false}.
	 * <p>This just serves as a hint for the actual transaction subsystem;
	 * it will <i>not necessarily</i> cause failure of write access attempts.
	 * A transaction manager which cannot interpret the read-only hint will
	 * <i>not</i> throw an exception when asked for a read-only transaction.
	 * @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()
	 */
	boolean readOnly() default false;

	/**
	 * Defines zero (0) or more exception {@link Class classes}, which must be a
	 * subclass of {@link Throwable}, indicating which exception types must cause
	 * a transaction rollback.
	 * <p>This is the preferred way to construct a rollback rule, matching the
	 * exception class and subclasses.
	 * <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)}
	 */
	Class<? extends Throwable>[] rollbackFor() default {};

	/**
	 * Defines zero (0) or more exception names (for exceptions which must be a
	 * subclass of {@link Throwable}), indicating which exception types must cause
	 * a transaction rollback.
	 * <p>This can be a substring, with no wildcard support at present.
	 * A value of "ServletException" would match
	 * {@link javax.servlet.ServletException} and subclasses, for example.
	 * <p><b>NB: </b>Consider carefully how specific the pattern is, and whether
	 * to include package information (which isn't mandatory). For example,
	 * "Exception" will match nearly anything, and will probably hide other rules.
	 * "java.lang.Exception" would be correct if "Exception" was meant to define
	 * a rule for all checked exceptions. With more unusual {@link Exception}
	 * names such as "BaseBusinessException" there is no need to use a FQN.
	 * <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)}
	 */
	String[] rollbackForClassName() default {};

	/**
	 * Defines zero (0) or more exception {@link Class Classes}, which must be a
	 * subclass of {@link Throwable}, indicating which exception types must <b>not</b>
	 * cause a transaction rollback.
	 * <p>This is the preferred way to construct a rollback rule, matching the
	 * exception class and subclasses.
	 * <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)}
	 */
	Class<? extends Throwable>[] noRollbackFor() default {};

	/**
	 * Defines zero (0) or more exception names (for exceptions which must be a
	 * subclass of {@link Throwable}) indicating which exception types must <b>not</b>
	 * cause a transaction rollback.
	 * <p>See the description of {@link #rollbackForClassName()} for more info on how
	 * the specified names are treated.
	 * <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)}
	 */
	String[] noRollbackForClassName() default {};

}
  基于源代码,我们可以发现在@Transactional,原来有这么多的属性可以进行配置,从而达到复杂应用控制的目的。具体各个属性的用法和作用,将在本文的后面逐一进行讲解和说明。

2.  使用@Transactional的Spring配置

     为了使用基于@Transactional的事务管理,需要在Spring中进行如下的配置:

  1.    <beans:bean id="transactionManager"  
  2.     class="org.springframework.orm.jpa.JpaTransactionManager">  
  3.     <beans:property name="dataSource" ref="dataSource" />  
  4.     <beans:property name="entityManagerFactory" ref="entityManagerFactory" />  
  5. </beans:bean>  
  6.   
  7. <!-- 声明使用注解式事务 -->  
  8. <tx:annotation-driven transaction-manager="transactionManager" />  
    <beans:bean id="transactionManager"
		class="org.springframework.orm.jpa.JpaTransactionManager">
		<beans:property name="dataSource" ref="dataSource" />
		<beans:property name="entityManagerFactory" ref="entityManagerFactory" />
	</beans:bean>

	<!-- 声明使用注解式事务 -->
	<tx:annotation-driven transaction-manager="transactionManager" />
    dataSource是在Spring配置文件中定义的数据源的对象实例,EntityManagerFactory是基于JPA使用的实体类管理器:org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean。这些都是用来配置与数据库的连接信息,本质上,@Transactional使用了JDBC的事务来进行事务控制的。

    <annotation-driven>标签的声明,则是在Spring内部启用@Transactional来进行事务管理,类似开关之类的声明。

3.  @Transactional之value

    value这里主要用来指定不同的事务管理器;主要用来满足在同一个系统中,存在不同的事务管理器。比如在Spring中,声明了两种事务管理器txManager1, txManager2.

然后,用户可以根据这个参数来根据需要指定特定的txManager.

   那有同学会问什么情况下会存在多个事务管理器的情况呢? 比如在一个系统中,需要访问多个数据源或者多个数据库,则必然会配置多个事务管理器的。

4.   @Transactional之propagation

      Propagation支持7种不同的传播机制:

  •  REQUIRED
               业务方法需要在一个事务中运行,如果方法运行时,已处在一个事务中,那么就加入该事务,否则自己创建一个新的事务.这是spring默认的传播行为.。 
  •  SUPPORTS: 
               如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分,如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。
  •  MANDATORY:
               只能在一个已存在事务中执行,业务方法不能发起自己的事务,如果业务方法在没有事务的环境下调用,就抛异常
  •  REQUIRES_NEW
             业务方法总是会为自己发起一个新的事务,如果方法已运行在一个事务中,则原有事务被挂起,新的事务被创建,直到方法结束,新事务才结束,原先的事务才会恢复执行.
  •  NOT_SUPPORTED
           声明方法需要事务,如果方法没有关联到一个事务,容器不会为它开启事务.如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行.
  • NEVER:
              声明方法绝对不能在事务范围内执行,如果方法在某个事务范围内执行,容器就抛异常.只有没关联到事务,才正常执行.
  •  NESTED:

          如果一个活动的事务存在,则运行在一个嵌套的事务中.如果没有活动的事务,则按REQUIRED属性执行.它使用了一个单独的事务, 这个事务拥有多个可以回滚的保证点.内部事务回滚不会对外部事务造成影响, 它只对DataSourceTransactionManager 事务管理器起效.

     其实大家最感到困惑的是REQUIRED_NEW和NESTED两种不同的传播机制,功能类似,都涉及到了事务嵌套的问题,那两者有何区别呢?该如何正确使用这两种模式呢?

        以下是摘自Spring的文档:
           PROPAGATION_REQUIRES_NEW : uses a completely independent transaction for each affected transaction scope. In that case, the underlying physical transactions are different and hence can commit or roll back independently, with an outer transaction not affected by an inner transaction's rollback status.
         内部的事务独立运行,在各自的作用域中,可以独立的回滚或者提交;而外部的事务将不受内部事务的回滚状态影响。 
         ROPAGATION_NESTED : uses a single physical transaction with multiple savepoints that it can roll back to. Such partial rollbacks allow an inner transaction scope to trigger a rollback for its scope, with the outer transaction being able to continue the physical transaction despite some operations having been rolled back. This setting is typically mapped onto JDBC savepoints, so will only work with JDBC resource transactions.
       NESTED的事务,基于单一的事务来管理,提供了多个保存点。这种多个保存点的机制允许内部事务的变更触发外部事务的回滚。而外部事务在混滚之后,仍能继续进行事务处理,即使部分操作已经被混滚。 由于这个设置基于JDBC的保存点,所以只能工作在JDBC的机制智商。
       由此可知, 两者都是事务嵌套,不同之处在于,内外事务之间是否存在彼此之间的影响;NESTED之间会受到影响,而产生部分回滚,而REQUIRED_NEW则是独立的。


转载地址:http://blog.youkuaiyun.com/blueheart20/article/details/44654007/

<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 特性,而无需编写繁琐的事务管理代码。理解其工作原理(代理、拦截器、事务管理器)对于正确使用和排查事务相关问题至关重要,同时要特别注意可见性、自调用、异常处理和传播行为等常见陷阱。它广泛应用于简化业务层的事务管理,支持多种持久化技术,并在集成测试中发挥重要作用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值