讲知识最好是深入浅出。
把深奥的东西用浅显的道理讲出来。
所谓浅显就是人们容易感知,人们熟悉它,了解它,生活中能遇到它,形容它。
今天讲讲脏读,不可重复读,幻读,这几个数据库事务里一定会提起来的词语。
讲这个之前先把4个隔离级别熟悉一下。
然后我讲下怎么来记忆这4个级别,很多人可能知道但是老记不住或者记混了。
我们把四个级别按照隔离程度排序1234.
先记3
3是啥
找一个恶趣味
3P
就代表着 单词里有 p
Repeatable
可重复读
然后1是啥
1是最低
最弱
最无能
无能就是 unable
un这个 un那个 un就是无能
Uncommitted 未提交就是1
2序号大点
牛逼点
比无能要有能一点
就不是Un了
就能 commit了
4是串行化
4就是死嘛
死就是S
所以有一个
Serializalabl
这样1234都容易记住了。
然后我们来说一些场景来分别描述脏读,不可重复读,幻读。
假如有一张表 account
表里有一条数据 代表ID=1的账号有1000元钱
#1先看看脏读的场景
假设有两个用户A B 同时在连接数据库在做操作
用户A
set session transaction isolation level read uncommitted;
start transaction;
select * from account;
用户B
set session transaction isolation level read uncommitted;
start transaction;
update account set account=account-200 where id = 1;
在如上的这种SQL的场景里
可能发生什么事情呢?
用户B执行到一半反悔了 回滚了
用户A得到了一个800
这个800是个假800
他认为账号里有800元 其实不是
他读的是一个尚未提交的数据 是一个半路上的数据
举一个军队里的形象的例子:你作为一个土匪窝里的小兵,你从山下过来山上问今天晚上的口令是什么,而口令正在讨论中,二当家说的口令就定为“整个西班牙晴空万里”吧,你走到大营门口问站岗的王二狗,王二狗就听到了这句,然后告诉你这就是今晚的口令,你屁颠屁颠的下山了,结果二当家说完了以后,大当家上去就是一个耳掴子,什么玩意,西班牙西班牙的,今天的口令叫“天王盖地虎”,你不知道后来发生的事情,晚上巡夜的时候,口令错误,被打死了,你临死前感慨,王二狗真TM脏啊,这就是脏读,读了尚未决定的值。
#2再来看看不可重复读
用户B
set session transaction isolation level read committed;
start transaction;
update account set account=account-200 where id=1;
用户A
set session transaction isolation level read committed;
start transaction;
select * from account; //读一次
select * from account; //又读一次
select * from account; //再读一次
在如上的场景里可能发生什么事呢
用户A在同一个事务里
第一次读是1000
第二次读是800
读出了不同的结果,A就懵逼了。
注意是同一个事务哈,不能再往下分割了。
下一个事务再来,人家发生了变化是正常的。
还是举一个例子,你是作为一个土匪窝里的小兵,你从山下过来山上问今天晚上的口令是什么,站岗的王二狗说,是“小鸡炖蘑菇”,然后风有些大,你想确认一下,说道:Pardon? can you say again?
王二狗说是“清风扶杨柳”,这个时候你怒了,“你小子玩儿我呢吧?刚才说的是这个吗”,问一遍一个答案,这就是不可重复读。
#3再来看看幻读。
用户A
set autocommit = 0;
set session transaction isolation level repeatable read;
start transaction;
select * from account;
select * from account;
select * from account;
INSERT INTO `baseinfo`.`account` (`id`, `account`) VALUES ('2', '1000.00');
COMMIT;
用户B
set autocommit = 0;
set session transaction isolation level repeatable read;
start transaction;
update account set account=account-200 where id=1;
INSERT INTO `baseinfo`.`account` (`id`, `account`) VALUES ('2', '1000.00');
COMMIT;
这里可能发生什么场景呢。
用户A先查询后插入,非常正经,非常正派的做法。
结果呢,因为用户B给插入了ID=2,造成A老是插不进去。
用户A疯了 我查询了3次,数据表里没有id为2的数据啊,我怎么就插入不进去呢。
举一个实际的例子,两拨土匪打仗了,你作为一个土匪窝里的小兵,然后你去一个山头上架设电话线,为了保证安全,去之前你首先问一次,那个山头上有没有敌人啊,回答说没有,不放心你又问了一次,那个山上有没有敌人啊,回答说没有,最后马上要上山了,你又问一次,有没有敌人啊,回答说没有,结果你刚爬上山,一梭子子弹打过来,给你打残废了。这个时候你脑子蒙蒙的,说道TM的老子是幻听了吗,不是说的没有敌人吗?
这就是幻读。