
mysql
一、 乐观锁 和 悲观锁
乐观锁 和 悲观锁 是实现并发操作的两种不同的 加锁思想,其中:
-
乐观锁假设:操作能成功,不需要事先加锁,只要在真正提交时验证本次修改是否可以提交,如果不可以提交,则重新尝试更新。 -
悲观锁假设:操作不能成功,需要事先对要更新的数据加锁,操作成功后再释放锁,以便其他线程能获得锁。
二、 MVCC 实现思路
MVVC,全名 Multi-Version Concurrency Control,即:多版本并发控制,是 MySQL 的 InnoDB 存储引擎下,repeatable-read 和 read-committed 隔离级别时事务的 乐观锁 的实现方案。大概的实现思路是:
- 在 InnoDB 的表中增加两个隐藏字段:
创建版本号和删除版本号。 - 在开启一个事务时,生成一个事务的版本号。
- 被操作的数据,会临时生成一条新的记录,这条
临时记录对其他事务时不可见的(事务的隔离性原则)。 - 如果事务执行成功,会将
更新后的数据和事务的版本号更新到真实的记录上,同时删除临时记录。 - 因此,在
MVCC中,其实是不存在锁的,既避免了争锁等问题,又保证了并发操作。
三、 MVCC 下的 CURD
1. insert
将当前的事务版本号作为数据的创建版本号。
2. delete
将当前的事务版本号作为数据的删除版本号。
3. update
- 基于要删除的行,复制出一个临时行。
- 将当前事务的版本号设置为要删除数据的删除版本号。
- 将当前事务的版本号设置为临时行的创建版本号。
- 事务提交时,用临时行替换要删除的行。
4. select
同时满足一下两个条件的数据,会作为查询结果返回:
- 条件一:数据的创建版本号小于等于事务版本号。即:在事务开始前,数据是存在的。
- 条件二:数据的删除版本号未定义或者大于事务版本号。即:在事务开始前,数据还没被删除。
四、MVCC 优缺点
1. 优点:
- 因为
MVCC中并没有使用锁,从而避免了锁的资源浪费和争锁、死锁等问题。 - 使用两个隐藏的版本号和事务版本号巧妙的解决了
不可重复读的问题。 -
读不加锁,速度快。 -
读和写不冲突。
2. 缺点:
- 存储了更多数据(两个隐藏的版本号字段)
- 增加了很多检查工作和处理完后的善后工作。
- 只能在
repeatable-read和read-committed隔离级别下工作。 -
read-uncommitted隔离级别下MVCC每次都获取到最新的事务版本号。 -
serializable隔离级别时,读操作锁定了返回的每一行。