MySQL隔离机制
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 --表级独占锁
查询、更新行数据的时候会在表上加意向锁;分为意向共享锁和意向独占锁