mysql-隔离级别
事务隔离级别
https://mp.weixin.qq.com/s/x_7E2R2i27Ci5O7kLQF0UA
未提交读 幻读+重复读+脏读
提交读 幻读+重复读
重复读 幻读
mysql重复读解决了幻读问题,mvcc解决了快照读的幻读问题,而间隙锁解决了当前读幻读问题。
串行 (读加共享锁,写加独占锁)
一些锁
乐观锁cas原理。读version+改version+1和相关字段,失败就再再来。
独占锁 for update
一个占了,能读能写,其他都不能占。
读锁 LOCK IN SHARE MODE
一个占了,只能读,其他也能占读锁,但是写锁加不了。
窗口1:
set autocommit = 0;
start TRANSACTION;
select * from com_code where id = 3 LOCK IN SHARE MODE;
窗口2:
转呀转啊,转菊花,就是不执行。
UPDATE `ae_plat`.`com_code` SET `code` = 33 WHERE `id` = 3;
意向锁
表级别的,读锁前要加读意向锁,写锁前要加写意向锁。
比如现在有个id为3的读锁,现在要加个全表的写锁。发现已经有了读意向锁,所以等待,等读意向锁释放。
间隙锁
重复读隔离级别,引入避免幻读。
间隙锁只对于有索引的,没有索引的只能全锁。
事务测试
测试脏读
- 关闭自动提交,执行插入sql。
- 另开一个窗口,查询数据查不到此条数据,说明没有脏读问题。
测试 不可重复读
- 查id是58的这条数据,发现title是
测试视频1111
。 - 在另外的窗口,执行
update
这条数据title改为6666
。
然后再执行第一个窗口中的select
语句,结果和原来的一样,没有变成6666
说明没有不可重复读的问题。
测试幻读
窗口1:
1 1 222
2 1 11
3 1 10
5 2 9
set autocommit = 0;
start TRANSACTION;
select * from com_code where id<5;//查出3条
窗口2执行:
INSERT INTO `ae_plat`.`com_code`(`id`, `code`, `agent_id`) VALUES (4, 2, 10);
窗口1:
select * from com_code where id<5;//再次执行,结果还是3条,不存在幻读问题
mysql避免幻读相关
快照读(mvcc实现)
上面例子,窗口1里的select
就是快照读,快照读会读本事务里的快照数据就是缓存,不会读到当前数据里的id
为4数据。
当前读
增删改,是当前读,不读缓存,如果把select
改为update
所以数据的code
为5。最后新插入的那条数据code
就会变成5。
mysql比sql标准厉害,rr级别也可以避免幻读,但是存在增删改这种当前读的情况,还是会发生幻读。
怎么避免当前读的幻读问题呢?加锁。
set autocommit = 0;
start TRANSACTION;
select * from`ae_plat`.`com_code` WHERE `id` < 5 for update;
这时候执行insert插入,就会菊花转呀转。这咋实现的,这就是间隙锁,对不存在的数据加锁,然后再去执行update,提交事务,就不会把新插入的数据也修改了,这就是利用间隙锁避免当前读出现幻读问题的实现。
一些命令
1:查看当前的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
杀死事务进程id(就是上面命令的trx_mysql_thread_id列)
2:查看当前锁定的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
3:查看当前等锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;