MySQL事物的四大特性:
原子性,一致性,隔离性,持久性。
事物的隔离性是如何保证的?
事物的隔离性由MVCC和锁保证的。
可重复读隔离界别下的快照读(普通select),是通过MVCC来保证事务隔离性的,当前读(update、select...for update)是通过行级锁来保证事务的隔离性的。
事物的持久性是如何保证的?
事物的持久性是由redo log保证的,因为MySQL通过WAL(先写日志再写数据)机制,在修改数据的时候,会将本次对数据页的修改以redo log的形式记录下来,这个时候更新就算完成了。Buffer Pool的脏页会通过后台线程刷盘,即使脏页还没刷盘的时候发生了数据库重启,由于修改操作都记录到了redo log,之前已经提交的记录都不会丢失,重启后通过redo log,恢复脏页数据,从而保证了事物的持久性。
事物的原子性是如何保证的?
事物的原子性是通过undo log实现的,在事务还没提交前,历史数据会记录在undo log中,如果事务执行过程中,出现了错误或者用户执行了ROLLBACK语句,MySQL可以利用undo log中的历史数据,将数据恢复到事务开始之前的状态,从而保证了事物的原子性。
MySQL的隔离级别:
MySQL默认的隔离级别有可重复读,除此之外,MySQL还支持读未提交,读提交,串行化三个隔离界别
我了解到的并发问题存在脏读,不可重复读,幻读这三种,不同的隔离级别,解决的问题也各不相同。
出现的问题:
脏读,不可重复读,脏读的意思:
- 脏读是指一个事务读取了另一个事务还未提交的数据,如果另一个事务回滚,则读取的数据是无效的。脏读可能导致数据的不一致性
- 不可重复读是指一个事务多次读取同一条数据,但是在此期间另一个事务修改了该记录,导致前后读取的数据不一致,不可重复读可能导致数据的不一致性
- 幻读是指一个事务多次执行同一个查询,但是在此期间另一个事务插入了符合该查询条件的新数据,导致前后数据不一致,幻读可能导致数据的不完整性。
解决的问题:
- 读未提交一个问题也没有解决
- 读已提交避免了脏读的问题,但是还存在不可重复读和幻读两个问题
- 可重复读避免了脏读和不可重复读的问题,不过对于幻读问题是很大程度上避免了,没有完全避免
- 串行化是所有问题都可以避免,但是事务的并发性能是最差的。
MySQL提供了两种查询方式,一种是快照读,就是普通的select语句,另一种是当前读,比如select for update 语句。不同的查询方式,解决不可重复读问题的方式是不一样的。
可重复读隔离级别下如何解决不可重复读的:
针对快照读的话,是通过MVCC机制来解决的,在可重复读隔离级别下,第一次select查询的时候,会生成readview,在第二次执行select查询的时候,会复用这个readview,这样前后两次查询的记录都是一样的,不会读到其他事务更新的操作,这样就不会发生不可重复读的问题了。
针对当前读的话,靠行级锁中的记录所来实现的,在可重复读隔离级别下,第一次select for update 语句查询的时候,会对记录加next-key锁,这个锁包含了记录锁,这时候如果其他事务更新了加了锁的记录,都会被阻塞住,这样就不会发生不可重复读问题了。
可重复读隔离界别下如何解决幻读:
针对快照读的话,是通过MVCC机制来解决的,在可重复读隔离级别下,第一个select查询的时候,会生成readview,在第二次执行select查询的时候,会复用这个readview,这样前后两次查看的结果集都是一样的,必会读到其他事务新插入的记录,这样就不会产生幻读的问题了。
针对当前读的话,靠行级锁中的间隙锁来实现的,在可重复读隔离级别下,第一个select for update语句查询的时候,会对记录加上next-key锁,这个锁包含间隙锁,这时候如果其他事务往这个间隙锁插入新的记录的话,都会被阻塞住,这样就不会产生幻读的问题了。
可重复读隔离界别下,MVCC完全解决了不可重复读的问题吗?
如果前后两次查询都是快照读的话,就是普通select的话,那么就不会产生不可重复读的额外难题。但是如果第一次查询的是快照读,第二次查询的当前读的话,那么就可能会发生不可重复读的的问题。
可重复读隔离级别下为什么不能完全解决幻读的问题?什么情况下会出现幻读的问题?
在可重复读级别场景下,当先快照读再进行当前读的场景下可能会出现幻读的问题。
解决方法:
在开启事务之后,马上执行select ... for update语句,他会对记录加上临键锁(next-key锁),这样就可以避免其他事务插入一条新纪录,避免了幻读的问题。
1222



被折叠的 条评论
为什么被折叠?



