前言
面试中,Spring的事务问得比较多,特别是Spring事务的传播行为和隔离级别,下面就让我们一起来复习下,首先我们要清楚事务的四大特征(ACID):
- 原子性(atomicity)
- 一致性(consistency)
- 隔离性(isolation)
- 持久性(durability)
1、概念
Spring有两种事务处理方式,一种是声明式事务,另外一种是编程式事务。
- 声明式事务:底层建立在IoC和AOP的基础上,在方法的前后进行拦截,在方法执行前创建或者加入一个事务,方法执行后提交或者回滚事务。
- 编程式事务:在方法的前后手动的开启和关闭事务,控制的粒度比声明式事务要小,可以达到代码块级别,但代码会很臃肿和复杂,项目中一般不会用。
2、声明式事务
在配置声明式事务管理的时候,我们用到最多的是注解方式,我们看下@Transactional这个注解的源码:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
//定义事务管理器,这里的value是IoC容器中的Bean id
@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 {};
}
上面的属性中,这里重点解释传播行为和隔离级别
3、传播行为
下面是定义传播行为Propagation枚举类的源码:
public enum Propagation {
//支持当前事务(如果当前存在事务,则加入到当前事务,总共一个事务),如果不存在 就新建一个(默认)
REQUIRED(0),
//支持当前事务,如果不存在,就不使用事务
SUPPORTS(1),
//支持当前事务,如果不存在,抛出异常
MANDATORY(2),
//如果有事务存在,挂起当前事务,新建一个新的事务(新建的事务是独立,与当前事务无关)
REQUIRES_NEW(3),
//以非事务方式运行,如果有事务存在,挂起当前事务
NOT_SUPPORTED(4),
//以非事务方式运行,如果有事务存在,抛出异常
NEVER(5),
//如果当前事务存在,则嵌套事务执行,作为当前事务中的一个子事务(依赖外层的事务,外层事务失败,子事务也要回滚)
NESTED(6);
private final int value;
private Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
4、隔离级别
先看下几个基本的概念:
- 脏读:一个事务读取到另一事务未提交的更新数据。
- 不可重复读:在同一事务中, 第一次读取和第二次读取过程中,有另外一个事务更新提交了数据,导致多次读取同一数据返回的结果不同。
- 幻读 : 第一个事务正在查询符合某一条件的数据,这时,另一个事务又插入了一条符合条件的数据,第一个事务在第二次查询符合同一条件的数据时,发现多了一条前一次查询时没有的数据,仿佛幻觉一样,这就是幻像读。
【提示】:不可重复读针对的是更新和删除操作导致数据不一致,幻读针对的是插入操作导致的数据不一致。
下面是定义隔离级别Isolation枚举类的源码:
public enum Isolation {
//Spring默认的隔离级别,使用数据库默认的事务隔离级别
//MYSQL: 默认为REPEATABLE_READ级别
//SQLSERVER: 默认为READ_COMMITTED
DEFAULT(-1),
//读取未提交数据(会出现脏读, 不可重复读) 基本不使用
READ_UNCOMMITTED(1),
//读取已提交数据(会出现不可重复读和幻读)
READ_COMMITTED(2),
//可重复读(会出现幻读)
REPEATABLE_READ(4),
//串行化(防止脏读,不可重复读外,还避免了幻像读,但花费代价很大)
SERIALIZABLE(8);
private final int value;
private Isolation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
结束语
本文较为详细的介绍了Spring事务的相关知识点,大家可以自己在本地亲自实践下,加深自己的理解。