事务隔离级别(4种)
- 读未提交
- 没做任何的事务隔离和锁的机制,所以他是最不安全的,但是效率最高。存在脏读、不可重复读、幻读!
- 读已提交
- 在每次执行查询的时候,会执行一个内存快照,查询快照中的数据。
- 快照中不会保存别的事务的未提交的数据,所以可以保证不会出现脏读
- 但是由于每次执行都出生成新的快照,如果在第一次快照和第二次快照之间有别的事务也进行了事务提交,再次生成的快照就和第一次的快照不同了,所以存在一个不可重复读问题,和幻读问题!
- 可重复读
- 在整个事务开始的时候,创建一个全局的快照,那么在一个事务中的多次查询操作都会查询这一个快照数据,解决了不可重复读问题。
- 但是快照会新增其他事务的insert数据,也就是说在一次条件查询之后,别的事务插入一条数据并提交了,那么再次执行这个条件查询,该条件能够查出比上一次多的一条数据,这个叫幻读。
- 其实,mysql采用的可重复读已经解决了幻读的问题,通过行锁加间隙锁来实现。
- 例如一个student表有两个字段name和age,有两条数据:张三,20;李四,22.
现在我执行sql:update student set name=‘王五’where age=20;那么此时,会将age=20的数据加上行锁,同时在该数据的两边,也就是负无穷到20,20到22之间加上间隙锁,如果有另一个事务B来新增一条数据,且该数据中age的取值是在行锁或者间隙锁上的,那么需要等待前一个事务先完成。
- 串行化
- 读的时候加共享锁,允许其他事务并发读但是不能并发写;写的时候加排他锁,其他事务的读和写操作都不能够执行,必须等当前事务先执行完。安全性是最高的,但是同样的,基本并发能力会非常差。
脏读:指一个事务读取了另外一个事务未提交的数据。假设A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据。
不可重复读:指一个事务在一次事务内多次读取的数据不一致。假设事务A获取一个数据,然后A事务继续运行,此时事务B进来修改了该数据并提交事务了,然后事务A又来获取这个数据,结果发现这次和上一次获取的数据不一致。
幻读:是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。假设事务A在执行读取操作,需要两次统计数据的总量,前一次查询数据总量后,此时事务B执行了新增数据的操作并提交后,这个时候事务A读取的数据总量和之前统计的不一样,就像产生了幻觉一样,平白无故的多了几条数据,称为成为幻读。会发现,幻读和不可重复读是十分相似的,以致于很多人很难分辨它们,你只需要知道,它们最大的区别是:不可重复读读取到的是更新(update)数据,而幻读读取到的是插入(insert)数据。
什么叫‘创建一个快照’?如果我的数据有100G,是要全量拷贝一份吗?
快照:学名叫‘一致性读视图’,他是MVCC实现读提交和可重复读的核心。Innodb里面,每个事务都有一个自己的事务ID,同时每行数据也是有多个版本的,每行数据中会包含一个row trx_id 隐式字段,就是存放当前这条数据的事务ID。那么就很简单了,其实就是去查询数据库的时候带上自己当前事务的事务ID就行了。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读(Read uncommitted) | 可能 | 可能 | 可能 |
已提交读(Read committed) | 不可能 | 可能 | 可能 |
可重复读(Repeatable read) | 不可能 | 不可能 | 可能 |
可串行化(Serializable ) | 不可能 | 不可能 | 不可能 |
Spring事务传播行为(7种)
传播行为 | 描述 |
---|---|
REQUIRED(默认) | 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。 |
SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
MANDATORY | 支持当前事务,如果当前没有事务,就抛出异常。 |
REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
NESTED | 如果存在事务,则运行在一个嵌套的事务中。 如果没有活动事务, 则按REQUIRED 属性执行。 |