mysql隔离级别
- 读未提交:一个事务B还没提交,它的修改就被别的事务A读到了。
- 读已提交:一个事务B提交后,它的修改被其他事务A看到了。
- 可重复读:一个事物B提交前和提交后,事务A都无法读到事务B的变更。
- 串行化:对同一行记录,当出现不同事物的读写冲突时,是通过串行化的方式解决的,后一个事务必须等前一个事务完成才能执行。
不同隔离级别产生的问题
- 脏读:读到了别的事务尚未提交(commit)的变更,别人没提交,我读到了。
- 不可重复读:别的事务提交了变更,被当前事务读到了。然后导致本事务多次select的结果不一样,读到了别的事务提交的内容。
- 幻读:也是读到了别的事务提交的内容,但是跟上面的不同之处在于,读到了原本不存在的记录。
事务隔离性的实现
一个是锁,一个是多版本并发控制(MVCC)。
InnoDB中,实现了两种标准的行级锁:
- 共享锁(S Lock),也叫读锁,读取数据的时候加锁
- 排它锁(X Lock),也叫写锁,删除或者更新一行数据的时候加锁
锁兼容和不兼容:
- 当一个事务A已经获得了行r的共享锁,那么另一个事务B可以立刻获得行r的共享锁,因为不会改变r的数值,这种叫做锁兼容。
- 如果这时候有事务C希望获得行r的排它锁,那么就必须等待事务A和事务B释放行r的共享锁之后,才能获得排它锁,这种叫做锁不兼容。
如果在update、insert的时候,不能进行select,那么服务的并发访问性能就太差了。因此,我们日常的查询,都是“快照读”,不会上锁,只有在update\insert\“当前读”的时候,才会上锁。而为了解决“快照读”的并发访问问题,就引入了MVCC。
多版本并发控制MVCC
什么是快照?
系统创建过的事务id:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
事务A启动,拍个快照
此时未提交的事务id有:7,8,9
快照:数组array[7,8,9] + 高水位16(15+1)
快照的可见性:
-
如果版本号小于“低水位”,说明事务已经提交,那肯定 可见;
-
如果版本号大于“高水位”,说明这行数据的这个事务id版本是在快照后产生的,那肯定 不可见;
-
如果版本号在事务数组array中,说明这个事务还没提交,所以 不可见;
-
如果版本号不在事务数组array中,且低于高水位,说明这个事务已经提交,所以 可见;
-
当然,无论什么时候,自己的事务id中的任何变化,都是可见的
快照的创建时间:
-
“读未提及”级别下,没有一致性视图
-
“读已提交”级别下,会在 每个SQL开始执行的时候 创建一致性视图
-
“可重复读”级别下,会在 每个事务开始的时候 创建一致性视图
-
“串行化”级别下,直接通过加锁避免并发问题