事务传播行为及四种事务隔离级别

171 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情

一、事务属性的定义

public interface TransactionDefinition {

  int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
//默认隔离级别,和数据库的隔离级别一致
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
	//默认不超时
int TIMEOUT_DEFAULT = -1;

}

二、事务的七种传播行为

事务传播行为是为了解决业务层方法之间互相调用的事务问题

public enum Propagation {

    REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

    SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

    MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

    REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

    NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

    NEVER(TransactionDefinition.PROPAGATION_NEVER),

    NESTED(TransactionDefinition.PROPAGATION_NESTED);
    }
  • @Transactional(propagation=Propagation.REQUIRED) 如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)

  • @Transactional(propagation=Propagation.NOT_SUPPORTED) 容器不为这个方法开启事务

  • @Transactional(propagation=Propagation.REQUIRES_NEW) 不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务

  • @Transactional(propagation=Propagation.MANDATORY) 必须在一个已有的事务中执行,否则抛出异常

  • @Transactional(propagation=Propagation.NEVER) 必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)

  • @Transactional(propagation=Propagation.SUPPORTS) 如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务。

image.png

三、事务隔离级别

事务的隔离级别是为了解决mysql出现的一些问题,比如脏读、不可重复读、幻读等。

public enum Isolation {

  DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),

  READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),

  READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),

  REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),

  SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
}

那么什么是事务的脏读、不可重复读、幻读?

脏读: 脏读就是一个事物未提交的数据,被另外一个事务读到了,显然这种情况不可接受。

不可重复读: 不可重复读是指在一个事务内,多次读同一数据,前后读取的结果不一致。

幻读: 事务A对表中的一个数据进行了修改,这种修改涉及到表中的全部数据行。同时事务B也修改了这个表中的数据,这种修改是向表中插入一行新数据。那么就会发生操作事务A的用户发现表中还存在没有修改的数据行,就好像发生了幻觉一样。

事务的隔离级别及解决的问题:

image.png

1)TransactionDefinition.ISOLATION_DEFAULT : 使用后端数据库默认的隔离级别,MySQL默认采用的 REPEATABLE_READ(可重复读) 隔离级别;Oracle 默认采用的 READ_COMMITTED 隔离级别。

2)TransactionDefinition.ISOLATION_READ_UNCOMMITTED :最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

3)TransactionDefinition.ISOLATION_READ_COMMITTED : 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

4)TransactionDefinition.ISOLATION_REPEATABLE_READ : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生

5)TransactionDefinition.ISOLATION_SERIALIZABLE : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。