spring事务机制是spring提供的一种事务管理机制,他是基于Aop和mysql的事务机制来实现的。
在spring中管理事务主要是通过AOP和事务拦截器来实现,当Spring应用程序被事务注解标记后,事务拦截器会拦截该方法的调用,并在方法执行前后进行事务管理相关操作。
spring事务实现流程
1 基于AOP和mysql事务机制 ,在AOP底层默认选择JDkProxy这种动态代理方式,代理这个被
标注的方法并进行拦截和事务操作
2 对于使用了@Transactional注解的Bean,会创建一个代理对象作为Bean
3 当调用代理是,会会首先判断是否加上了该注解
4 如果加了这个注解 ,则利用事务管理器创建一个数据库链接
5 修改数据库链接的自动提交属性为false,禁止连接的自动提交
6 执行完当前方法会执行SQL
7 执行完当前方法后,如果没有出现异常就直接提交事务
8. 如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
9. Spring事务的隔离级别对应的就是数据库的隔离级别
10. Spring事务的传播机制是Spring事务自己实现的,也是Spring事务中最复杂的
11. Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为需要
新开一个事务,那么实际上就是先建立一个数据库连接,在此新数据库连接上执行sql
@Transactional
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default -1;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
事务传播行为
事务的传播行为用于控制事务方法之间的交互和事务边界的扩展。在Spring中,@Transactional注解的propagation属性用于设置事务的传播行为。
-
REQUIRED(默认):如果当前没有事务存在,则创建一个新的事务;如果当前已存在事务,则加入到当前事务中。这是最常用的传播行为,也是默认的传播行为。
-
SUPPORTS:如果当前存在事务,则加入到当前事务中;如果当前没有事务,则以非事务的方式执行。
-
REQUIRES_NEW:每次都创建一个新的事务,如果当前已存在事务,则将当前事务挂起。
-
NOT_SUPPORTED:以非事务的方式执行操作,如果当前存在事务,则将当前事务挂起。
-
NEVER:以非事务的方式执行操作,如果当前存在事务,则抛出异常。
-
MANDATORY:如果当前存在事务,则加入到当前事务中;如果当前没有事务,则抛出异常。
隔离级别
事务的隔离级别指定了事务之间读取数据时的隔离程度,即决定了一个事务读取数据是否能看到其他事务的未提交写操作或者对同一资源的并发读写等情况。
以下是几种常见的事务隔离级别:
-
DEFAULT(数据库默认隔离级别):数据库使用的默认隔离级别。
-
READ_UNCOMMITTED:最低的隔离级别,允许读取未提交的数据,可能导致脏读。
-
READ_COMMITTED:允许读取已提交的数据,防止脏读,但可能导致重复读。
-
REPEATABLE_READ:事务期间保证读取的数据一致性,防止脏读和不可重复读,但可能导致幻读。
-
SERIALIZABLE:最高的隔离级别,通过对事务进行串行化执行来防止脏读、不可重复读和幻读
当使用@Transactional注解时,还可以配置其他属性来进一步控制事务的行为。
1. readOnly属性:用于指定事务是否为只读事务。如果设置为true,则表示该事务只会读取数据,不会对数据进行修改。设置为只读事务可以提高性能。
@Transactional(readOnly = true)
public void readOnlyTransaction() {
// 只读事务
}
- timeout属性:用于指定事务的超时时间,单位为秒。如果方法执行时间超过设置的超时时间,则事务会自动回滚。
@Transactional(timeout = 10)
public void timedTransaction() {
// 设置事务超时时间为10秒
}
- rollbackFor和noRollbackFor属性:用于指定事务回滚的异常类型。rollbackFor属性指定的异常类型会触发事务回滚,而noRollbackFor属性指定的异常类型不会触发事务回滚。
@Transactional(rollbackFor = Exception.class, noRollbackFor = CustomException.class)
public void exceptionHandlingTransaction() throws Exception {
// 执行可能会抛出异常的操作
}
上述示例中,异常类型为Exception的异常会触发事务回滚,而CustomException异常不会触发事务回滚。
事务属性也可以被用在类级别上,以便对整个类中的所有方法应用相同的事务属性。
@Transactional
public class TransactionalClass {
// 类中的方法都应用相同的事务属性
}
需要注意的是,在使用@Transactional注解时,也可以指定多个属性,按需组合使用,以满足具体的业务需求。
总结一下,除了propagation和isolation属性外,@Transactional注解还提供了其他属性,如readOnly、timeout、rollbackFor和noRollbackFor等。通过配置这些属性,我们可以更加细粒度地控制事务的行为,包括只读事务、超时处理和异常回滚策略等。这些属性可以根据具体的业务需求来配置,以实现更加灵活和可控的事务管理。
spring事务失效Spring事务失效可能出现在以下情况:
-
未将事务注解配置到相应的方法或类上:事务注解是声明事务的关键,如果忘记在方法或类上添加@Transactional注解,那么方法将不会被包装在事务中,事务将无法生效。
-
方法没有被代理:Spring的事务管理是通过AOP实现的,它会在运行时动态地生成代理对象来对被注解的方法进行增强。如果方法没有被代理,那么事务管理将无法生效。最常见的情况是在同一个类中的一个方法调用另一个方法,因为在同一个类中的方法调用不能被AOP拦截。
-
异常被捕获/捕获过早:通常情况下,当一个被@Transactional注解的方法内部抛出异常时,事务会被回滚。但是,如果异常在方法内被捕获并处理,那么异常将不会传播到上一层调用者,事务也不会回滚。如果需要让事务生效,可以将异常重新抛出或使用@Transactional(rollbackFor = Exception.class)配置。
-
事务嵌套:如果在相同的类中的一个方法(A)调用另一个方法(B)并且两个方法都被@Transactional注解标记,那么事务将无法生效,因为嵌套的事务默认是不生效的。要使内部方法的事务生效,可以将事务传播行为设置为NESTED。
-
事务方法被private修饰:Spring事务是通过动态代理实现的,而动态代理只能代理公共方法。如果将事务注解放在private方法上,事务将无法生效。修正方法是将私有方法更改为公共方法。
-
事务方法在同一个类内部被调用:默认情况下,Spring事务是通过基于代理的AOP实现的,同一个类内部调用被@Transactional注解标记的方法时,AOP拦截器将不会生效。解决方法是将@Transactional注解放在外部调用方法上,或者通过将当前类的实例注入到另一个类中来实现事务功能。
总之,Spring事务可能失效的原因有很多,需要仔细检查代码和配置,确保事务注解正确应用并且被触发。熟悉事务的特性和使用场景也有助于正确配置和管理事务。