MySQL隔离机制

174 阅读3分钟

1. 脏写、脏读、不可重复读、幻读等问题

1)脏写

2)脏读

无论是脏写还是脏读,都是一个事务去更新或查询了另一个事务未提交的数据,如果另一个事务回滚,

就出现了脏写、脏读的情况

3)不可重复读

不可重复读不是什么大问题,具体取决于是否允许不可重复读,如果业务要求事务期间每次读取的

数据都是一致的,这就是问题,需要解决

4)幻读

2. MySQL隔离机制

1)read uncommitted

不允许脏写(不允许两个未提交的事务同时更新一条数据),但是会出现脏读、不可重复读、幻读问题

2)read committed

不会出现脏写和脏读(查询不到别的事务未提交的数据),但是会出现不可重复读、幻读

3)repeatable read

不会出现脏写、脏读、不可重复读问题(事务一旦开启,别的事务提交后的值也不会读到),但是会出现幻读,

这里是mysql比较牛的地方,RR级别下可以解决幻读的问题,要借助于下面所讲的MVCC

4)serializable  

串行化执行,根本就不是并发,所以上述问题都不会出现

3. MVCC

讲MVCC之前,我们有必要聊下undo log版本链。

简单来说,我们每条数据都有两个隐藏的字段trx_id和roll_pointer,trx_id是最近一次更新数据的事务id, roll_pointer指向了你更新这个事务之前生成的undo log

再来看看基于undo log链的ReadView机制

简单说就是执行一个事务的时候,就会生成一个ReadView,里面有4个关键东西

1)m_ids --此时有哪些事务未提交

2)min_trx_id --m_ids里最小的值

3)max_trx_id --表示下一个事务生成时分配给它的id

4)creator_trx_id --当前事务id

4. 锁

1)独占锁(X锁)

脏写是绝对不允许的,是靠锁来实现的,让多个事务更新同一行数据串行化,避免同时更新

事务A要更新数据,一看该数据没有人锁定,立马创建一个锁,包含了自己的trx_id和等待状态,然后锁和数据

关联起来;此时事务B也想要更新数据,发现数据已经被加锁了,然后B也生成一个锁,但此时B是等待状态的

接着事务A更新完数据提交,会把锁释放掉。一旦锁释放,就会去找还有没有别的事务加锁了,找到B的锁把等

待状态改为false,然后唤醒事务B继续执行,此时事务B就获取到数据了

如果此时别的事务来读取这条数据会加锁嘛?不会,基于MVCC,避免了频繁加锁

2)共享锁(S锁)

select * from table lock in share mode会给当前数据加共享锁

此时明白了,独占锁和独占锁是互斥的,别的事务不可以更新操作;如果是查询,默认走MVCC不加锁,如果手

动加共享锁,也是互斥的;最后共享锁和共享锁是不互斥的

3)行锁(上述两种锁讲的就是行锁)

4)表锁(一般不会这样操作)

lock table *** read --表级共享锁

lock table *** write --表级独占锁

查询、更新行数据的时候会在表上加意向锁;分为意向共享锁和意向独占锁