前言 & mysql默认存储引擎的默认隔离级别
从MySQL 5.x开始, 默认的存储引擎已经由MyISAM换为了InnoDB
查看存储引擎信息:
show engines
查看mysql版本:
select version();
返回值:
version()5.7.28
InnoDB默认的隔离级别是RR(Repeatable read, 可重复读),但还可能存在幻读现象;
依据隔离级别逐级升高,mysql提供了如下四种隔离级别:
a) Read uncommitted(未提交读):最低级别,任何情况都无法保证
b) Read committed(已提交读):可避免脏读的发生 `Orancle等多数数据库的默认级别`
c) Repeateable read(可重复读):可避免脏读、不可重复读的发生`mysql的默认级别`
d) Serializable(可串行化):可避免脏读、不可重复读、幻读的发生
show table status from future where name='our_user'
查看&设置 全局or会话 的事务隔离级别
复现’幻读’
副标题: 以InnoDB存储引擎下默认的隔离级别RR(Repeatable read, 可重复读)为例
幻读会在 RU / RC / RR 级别下出现,SERIALIZABLE 则杜绝了幻读,但 RU / RC 下还会存在脏读,不可重复读,故我们就以 RR 级别来研究幻读,排除其他干扰。
注意:RR 级别下存在幻读的可能,但也是可以使用对记录手动加 X锁 的方法消除幻读。SERIALIZABLE 正是对所有事务都加 X锁 才杜绝了幻读,但很多场景下我们的业务sql并不会存在幻读的风险。SERIALIZABLE 的一刀切虽然事务绝对安全,但性能会有很多不必要的损失。故可以在 RR 下根据业务需求决定是否加锁,存在幻读风险我们加锁,不存在就不加锁,事务安全与性能兼备,这也是 RR 作为mysql默认隔是个事务离级别的原因,所以需要正确的理解幻读。
mysql默认的隔离级别Repeateable read(可重复读)
,是无法防止”幻读”现象出现的,复现如下:
执行事务1:
此时另起一个窗口,执行(干扰)事务2:
这时在事务1中,继续执行
报错
即事务1查到没有id=5的记录,同时有一个其他事物(事务2)执行对id=5进行了写入.事务1继续进行insert操作,报主键冲突….事务1就很疑惑:不对啊,我刚才查了,明明没有id=5的记录啊..
解决方案: 给事务1的查询语句加排它锁,这样事务2就无法进行写入