【MySQL】事务隔离级别详述
数据库中的三种锁
1. 写锁(Write Lock,也叫做排他锁 eXclusive Lock,简写为 X-Lock)
只有持有写锁的事务才能对数据进行写入操作,数据加持着写锁时,其他事务不能写入数据,也不能施加读锁。(不能读写)
2. 读锁(Read Lock,也叫做共享锁 Shared Lock,简写为 S-Lock)
多个事务可以对同一个数据添加多个读锁,数据被加上读锁后就不能再被加上写锁,所
以其他事务不能对该数据进行写入,但仍然可以读取。对于持有读锁的事务,如果该数据只有一个事务加了读锁,那可以直接将其升级为写锁,然后写入数据。(能读不能写)
3. 范围锁(Range Lock)
对于某个范围直接加排他锁(写锁),在这个范围内的数据不能被读取,也不能被写入。
不要把范围锁理解成一组排他锁的集合,加了范围锁后,不仅无法修改该范围内已有的数据,也不能在该范围内新增或删除任何数据,这是一组排他锁的集合无法做到的。
(范围内不能读写)
SQL 标准的事务隔离级别包括
- 读未提交(read uncommitted):一个事务还没提交时,它做的变更就能被别的事务看到。
- 脏读(Dirty Reads):其它事务读取到未提交的数据,但是原事务数据回滚了,导致其它事务读取到脏数据
- 读未提交在数据上完全不加锁
- 读已提交(read committed):一个事务提交之后,它做的变更才会被其他事务看到。
- 不可重复读问题(Non-Repeatable Reads):两次重复执行的查询结果可能会不一样(两次查询过程中数据被修改)。原因是读已提交的隔离级别缺乏贯穿整个事务周期的读锁,无法禁止读取过的数据发生变化。
- 读已提交对事务涉及到的数据加写锁,会一直持续到事务结束,但加的读锁在查询操作完成后就马上会释放
- 可重复读(repeatable read):一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
- 幻读问题(Phantom Reads):指在事务执行的过程中,两个完全相同的范围查询得到了不同的结果集
- 可重复读的意思就是对事务所涉及到的数据加读锁和写锁,并且一直持续到事务结束,但不再加范围锁
- 假如这条 SQL 语句在同一个事务中重复执行了两次,并且这两次执行之间,恰好有另外一个事务在数据库中插入了一本小于 100 元的书籍(这是当前隔离级别允许的操作),那这两次相同的查询就会得到不一样的结果。
原因就是,可重复读没有范围锁来禁止在该范围内插入新的数据
SELECT count(1) FROM books WHERE price < 100 /* 时间顺序:1,事务: T1 */ INSERT INTO books(name,price) VALUES ('深入理解Java虚拟机',90) /* 时间顺序:2,事务: T2 */ SELECT count(1) FROM books WHERE price < 100 /* 时间顺序:3,事务: T1 */
- 串行化(serializable):顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
- 最高隔离性,性能低
- 对事务所有读、写的数据全都加上读锁、写锁和范围锁即可
视图
数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准
- 读未提交:直接返回记录上的最新值,没有视图概念(无视图,每次都读取最新的数据)
- 读已提交:这个视图是在每个 SQL 语句开始执行的时候创建的。(每个 SQL 语句开始执行时创建)
- 可重复读:这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。(事务启动时创建)
- 串行化:直接用加锁的方式来避免并行访问(无视图,通过加锁避免并发)
视图理解为数据副本,每次创建视图时,将当前『已持久化的数据』创建副本,后续直接从副本读取,从而达到数据隔离效果。
MySQL事务隔离级别
- 查看:show variables like 'transaction_isolation';
- 默认值:('transaction_isolation', 'REPEATABLE-READ');