关于事务一直有个误解,数据库的事务和Spring(语言)的事务有区别和联系吗,一直会有搞混。下面以Mysql数据库和Spring来做对比说明,梳理清楚。
Mysql 事务
隔离级别 值 名称 问题描述
Read Uncommitted 0 脏读 1:事务A,增、删、改,未提交;2:事务B,读取未提交的数据;3:事务A回滚;4:事务B看到的数据就是脏数据
Read committed 1 不可重复读 1:事务A,两次读操作;2:事务B,在事务A的两次读之间进行了修改;3:事务A第二次读的数据不一致
Repeatable Read 2 幻读 1:事务A做范围数据的批量修改,比如:age > 10 set class=small;2:事务B在 age > 10的范围内,只更新了一条数据,比如 age = 11 and id=111 set class=very small;3:事务A对事务B修改的数据丢失
Serializable 3 串行化 事务只能一个一个执行,最高等级,速度慢,避免了所有问题
Spring 声明式注解事务
使用声明式注解事务是比较简单的方式,将事务管理器交予 Spring 管理,在目标类或者目标方法上添加注解 @Transactional 即可
类型 名称 描述
事务传播行为 Propagation REQUIRED 当前如果有事务,Spring就会使用该事务;否则会开始一个新事务;默认选择
SUPPORTS 当前如果有事务,Spring就会使用该事务;否则不会开始一个新事务
MANDATORY 当前如果有事务,Spring就会使用该事务;否则会抛出异常
REQUIRES_NEW Spring总是开始一个新事务。如果当前有事务,则该事务挂起
NOT_SUPPORTED Spring不会执行事务中的代码。代码总是在非事务环境下执行,如果当前有事务,则该事务挂起
NEVER 即使当前有事务,Spring也会在非事务环境下执行。如果当前有事务,则抛出异常
NESTED 如果当前有事务,则在嵌套事务中执行。如果没有,那么执行情况与Transaction- Definition.PROPAGATION_REQUIRED一样
事务的隔离级别 Isolation DEFAULT 默认隔离级别(对大多数数据库来说就是 READ_COMMITTED)
READ_UNCOMMITTED 对应数据库 Read Uncommitted;产生 脏读、不可重复读、幻读
READ_COMMITTED 对应数据库 Read Committed;避免 脏读,产生不可重复读、幻读
REPEATABLE_READ 对应数据库 Repeatable Read;避免 脏读、不可重复读,产生 幻读
SERIALIZABLE 对应数据库 Serializable,隔离级别最高
@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 事务时,很少去修改事务的参数,直接使用默认值就行,导致对其配置参数不甚了解。上面通过对比 Spring 和 数据库的 事务描述,能理清楚两者之间的关系,清晰两者的定义,理解后再做到不混淆。