一、隔离级别
1. 并发产生的问题
- 脏读:一个事务读到了另一个未提交事务修改过的数据
- 幻读:一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来。
- 不可重复读:一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每次对该数据进行一次修改并提交后,该事务都能查询得到最新值
2. 事务隔离级别
- 读未提交(Read Uncommitted):并发下,A事务可以读取到B事务未提交过的数据。容易发生脏读、幻读、不可重复读的线像。一版情况下数据库不会使用该隔离级别。
- 读已提交(Read Committed):并发下,A事务比B事务开始执行,B事务如果要读取自己修改的数据,只能在A事务完成修改后已提交后,才能读取到。解决了脏读的问题,但可能发生幻读和不可重复读现像。
- 可重复读(Repeatable Read):并发下,B事务若想读到自己修改的数据,只能在A事务修改过数据并提交后,自己也提交事务后,才能读取到。及解决了脏堵、幻读的问题,单可能发生不可重复读。
- 可串行化(Serializable):并发下,最为严格的事务级别,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。但是执行效率低下,一般不采用。
隔离级别级别越高对于数据库的性能影响越大:可串行化>可重复读>读已提交>读未提交
MySQL和Spring中默认的事务隔离级别是“读已提交”。
二 事务传播
事务的传播行为主要分为七种。
- PROPAGATION_REQUIRED: 如果执行时,已经在一个事务中,就加入该事务。否则就开启一个新的事务。是默认的事务传播行为
- PROPAGATION_SUPPORTS:如果执行时,已经在一个事务中,就加入该事务。没有的话,就不以事务的方式进行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。
- PROPAGATION_MANDATORY:如果执行中,已经在一个事务中,就不能发起自己的事务。如果没有在一个事务中,就抛出异常。
- PROPAGATION_REQUIRES_NEW:如果执行中,已经在一个事务中,则这个事务将被挂起。并开启一个事务执行当前业务方法。执行完毕后,回复原来挂起的事务继续进行。
- PROPAGATION_NOT_SUPPORTED :总是非事务地执行,并挂起任何存在的事务。
- PROPAGATION_NEVER :总是非事务地执行,如果存在一个活动事务,则抛出异常。
- PROPAGATION_NESTED :如果业务方法在一个既有的事务中执行,则该业务方法将在一个嵌套的事务中进行;否则,按照TransactionDefinition.PROPAGATION_REQUIRED来对待。它使用一个单独的事务,这个事务可以有多个rollback点,内部事务的rollback对外部事务没有影响,但外部事务的rollback会导致内部事务的rollback。这个行为只对DataSourceTransactionManager有效。
三 SpringBoot中事务的配置
@Transactional源码
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
// 事务执行默认值
@AliasFor("transactionManager")
String value() default "";
// 事务执行默认值
@AliasFor("value")
String transactionManager() default "";
// 事务的传播级别
Propagation propagation() default Propagation.REQUIRED;
// 事务的隔离级别,默认的是读已提交
Isolation isolation() default Isolation.DEFAULT;
// 事务超时时长,-1代表永不超时
int timeout() default -1;
// 是否设置为只读的事务
boolean readOnly() default false;
// 设置需要进行回滚的异常类数组
Class<? extends Throwable>[] rollbackFor() default {};
// 设置需要进行回滚的异常类名称数组
String[] rollbackForClassName() default {};
// 用于设置不需要进行回滚的异常类数组
Class<? extends Throwable>[] noRollbackFor() default {};
// 用于设置不需要进行回滚的异常类名称数组
String[] noRollbackForClassName() default {};
}