引言:Spring的Transactional注解是框架中非常重要的一个特性,它为开发人员提供了方便的事务管理机制。Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中声明式事务用的比较多。声明式事务有两种方式,一种是在配置文件(xml)中做相关的事务规则声明,另一种是基于@Transactional 注解的方式。
一.什么是事务?
在软件开发中,事务是指由一系列操作组成的逻辑单元,这些操作要么全部成功地执行,要么全部回滚到初始状态,以保证数据的一致性和完整性。事务的使用非常重要,尤其是在处理数据库操作时。
事务是数据库管理系统中的一条或者多条操作指令的集合,这些操作指令被封装为一个整体,以保证数据库的完整性、一致性和原子性。在事务中,所有操作都成功,事务才能提交,否则回滚,这样可以确保数据的一致性和完整性。
事务具有以下四个特性:
原子性(Atomicity):事务是一个原子操作单元,其对数据的修改要么全部执行,要么全不执行。
一致性(Consistency):事务必须使数据库从一个状态改变为另一个状态。也就是说,事务开始之前和事务结束以后,数据库的完整性没有被破坏。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务。
持久性(Durability):一旦事务提交,则其结果永久保存在数据库中。即使系统崩溃,重新启动后数据库还能恢复到提交事务后的状态,保证事务的持久性。
在关系型数据库中,对事务有如下要求:
- 原子性:事务的原子性是指事务的操作要么全部完成,要么全部不完成。当一个事务中有一部分操作无法完成时,所有操作都需要回滚到操作前的状态。
- 一致性:一致性是指在一个事务操作前后,数据库的数据应保持一致性状态,即满足数据库的约束、外键约束和参照完整性的要求。
- 隔离性:隔离性是指在并发环境中,一个事务的执行不应影响其他事务的执行。
- 持久性:持久性是指一旦一个事务提交,则其结果永久保存在数据库中。即使系统崩溃,重新启动后数据库还能恢复到提交事务后的状态。
二、Spring的Transactional注解
在Spring框架中,Transactional注解是通过AOP(面向切面编程)来实现的。AOP允许我们在应用程序的关键部分插入代码,而不需要修改现有的业务逻辑。在事务管理中,我们可以使用Transactional注解将事务相关的行为织入到方法中。
Spring的Transactional注解提供了以下三个关键功能:
@Transactional:这个注解可以应用于类或方法上,表示该类或方法需要使用事务。当应用于类上时,该类中的所有public方法都将具有事务性。当应用于方法上时,只有该方法具有事务性。
@Transactional(readOnly = true):这个注解表示该事务只读,不会对数据库进行写操作。这对于只读取数据而不修改数据的情况非常有用。
@Transactional(rollbackFor = Exception.class):这个注解表示在指定异常的情况下回滚事务。例如,如果一个事务在执行过程中抛出了IOException,并且该事务的@Transactional注解中指定了rollbackFor = IOException.class,那么该事务将回滚并撤销之前的所有操作。
注解的定义
首先,让我们来看一下Transactional注解的定义。Transactional注解在Spring框架中的实现类是org.springframework.transaction.annotation.Transactional。该注解可以应用在方法级别或类级别,用于标记需要进行事务管理的方法或类。
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
// 事务的传播行为
Propagation propagation() default Propagation.REQUIRED;
// 事务的隔离级别
Isolation isolation() default Isolation.DEFAULT;
// 事务的超时时间
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
// 是否只读事务
boolean readOnly() default false;
// 触发事务回滚的异常
Class<? extends Throwable>[] rollbackFor() default {};
// 不触发事务回滚的异常
Class<? extends Throwable>[] noRollbackFor() default {};
}
关注属性
在Transactional注解中,有一些重要的属性需要我们关注:
1. propagation:指定事务的传播行为。它定义了事务之间相互调用时事务的作用范围和行为。常用的传播行为包括REQUIRED、REQUIRES_NEW、SUPPORTS等。
2. isolation:指定事务的隔离级别。它定义了多个事务同时对数据库进行读写操作时的处理方式。常用的隔离级别包括DEFAULT、READ_COMMITTED、READ_UNCOMMITTED等。
3. timeout:指定事务的超时时间。如果事务在指定的时间内没有完成,将会被自动回滚。
4. readOnly:指定事务是否只读。如果只进行读取操作,可以将readOnly属性设置为true,以提高性能。
5. rollbackFor和noRollbackFor:用于指定触发事务回滚和不触发事务回滚的异常类。可以通过这两个属性来精确控制事务的回滚行为。
实现原理
Transactional注解的实现原理是通过Spring AOP来实现的。Spring在运行时会通过AOP技术,对标记了@Transactional注解的方法进行代理,在代理对象中实现事务管理的相关逻辑。
具体地说,Spring会在@Transactional注解的方法执行前开启一个事务,并在方法执行后根据执行的结果来决定是提交事务还是回滚事务。当方法调用其他的@Transactional方法时,如果这些方法在调用时没有创建新的事务,则会加入到已有的事务中。
TransactionAspectSupport
是 Spring 框架中的一个类,它为事务切面的处理提供了支持。它提供了一些静态方法和实用函数,用于在代码中处理与事务相关的操作。
主要的功能和方法包括:
1. currentTransactionStatus()
:该方法用于获取当前事务的状态。它返回一个包含事务状态信息的 TransactionStatus 对象。
2. currentTransactionInfo()
:该方法用于获取当前事务的详细信息。它返回一个包含事务信息的 TransactionInfo 对象,包括事务定义、事务管理器等。
3. invokeWithinTransaction()
:该方法用于在方法调用内部执行带有事务的逻辑。它接受一个 TransactionCallback 对象作为参数,用于执行事务逻辑,并返回事务回调的结果。
4. isTransactionActive()
:该方法用于检查当前是否存在活动的事务。如果有活动的事务存在,则返回 true;否则返回 false。
在TransactionAspectSupport
类中,有一个processAnnotationTransaction
方法,它是@Transactional注解的核心处理方法。通过解析注解中的属性,创建TransactionAspectSupport类的实例,并调用实例的commitTransactionAfterReturning
或completeTransactionAfterThrowing
方法来实现事务的提交或回滚,由于源码比较多,感兴趣的小伙伴可以自行阅读一下。
不生效场景
Spring的Transactional注解在一些情况下可能不会生效,这些情况包括:
1. 未被Spring容器管理的对象:Transactional注解只对被Spring容器管理的Bean生效。如果一个对象不是由Spring容器创建和管理的,那么Transactional注解将不起作用。确保被注解的类或方法是由Spring容器管理的Spring Bean。
2. 缺少切面(Aspect):Transactional注解是通过AOP技术实现的,需要存在适当的切面来进行事务管理。如果应用程序中没有配置相应的切面或者AOP代理未生效,Transactional注解可能不会起作用。在配置文件中配置切面或使用@EnableTransactionManagement启用事务管理。
3. 同类内部方法的调用:当在同一个类中的一个@Transactional方法从该类中的另一个方法调用时,事务不会应用。这是因为Spring使用基于代理的AOP机制来实现事务,对于类内部方法的调用,不会触发代理的逻辑,因此事务注解不会生效。
4. 异常被捕获或处理:如果在@Transactional注解标记的方法中的异常被捕获或处理了,并且没有再次抛出异常,事务将不会回滚。默认情况下,只有未捕获的RuntimeException和Error才会触发事务回滚。如果遇到需要回滚事务的特定异常,可以使用rollbackFor属性来指定。
5. 方法不是public修饰:Transactional注解只对public修饰的方法生效。对于非public修饰的方法,例如private或protected方法,Transactional注解将不起作用。
三、总结
Spring的Transactional注解是一个强大且易用的工具,用于处理事务管理。它简化事务管理流程,提供声明式的事务管理方式,并具有灵活的事务控制能力。通过使用Transactional注解,开发人员可以更加专注于业务逻辑的实现,提升开发效率和代码的可维护性。因此,对于使用Spring框架的开发者来说,熟练掌握Transactional注解是非常重要的。
refs
# 深入解读Docker的Union File System技术