共计 2152 个字符,预计需要花费 6 分钟才能阅读完成。
MYSQL 中乐观锁的实现方法,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面丸趣 TV 小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
什么是 MVCC
MVCC 即 Multi-Version Concurrency Control,中文翻译过来叫多版本并发控制。
MVCC 是解决了什么问题
众所周知,在 MYSQL 中,MyISAM 使用的是表锁,InnoDB 使用的是行锁。而 InnoDB 的事务分为四个隔离级别,其中默认的隔离级别 REPEATABLE READ 需要两个不同的事务相互之间不能影响,而且还能支持并发,这点悲观锁是达不到的,所以 REPEATABLE READ 采用的就是乐观锁,而乐观锁的实现采用的就是 MVCC。正是因为有了 MVCC,才造就了 InnoDB 强大的事务处理能力。
MVCC 具体实现分析
InnoDB 的 MVCC, 是通过在每行记录后面保存两个隐藏的列来实现的, 这两个列,分别保存了这个行的创建时间,一个保存的是行的删除时间。这里存储的并不是实际的时间值, 而是系统版本号(可以理解为事务的 ID),每开始一个新的事务,系统版本号就会自动递增,事务开始时刻的系统版本号会作为事务的 ID. 下面看一下在 REPEATABLE READ 隔离级别下,MVCC 具体是如何操作的。
首先创建一张表:
create table yang( id int primary key auto_increment, name varchar(20) );
假设系统的版本号从 1 开始.
INSERT
InnoDB 为新插入的每一行保存当前系统版本号作为版本号。*** 个事务 ID 为 1:
start transaction; insert into yang values(NULL, yang insert into yang values(NULL, long insert into yang values(NULL, fei commit;
对应在数据中的表如下(后面两列是隐藏列, 我们通过查询语句并看不到)
SELECT
InnoDB 会根据以下两个条件检查每行记录:
InnoDB 只会查找版本早于当前事务版本的数据行(也就是, 行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的.
行的删除版本要么未定义, 要么大于当前事务版本号(这可以确保事务读取到的行,在事务开始之前未被删除), 只有条件 1、2 同时满足的记录,才能返回作为查询结果.
DELETE
InnoDB 会为删除的每一行保存当前系统的版本号 (事务的 ID) 作为删除标识.
看下面的具体例子分析: 第二个事务,ID 为 2:
start transaction; select * from yang; select * from yang; commit;
假设 1:
假设在执行这个事务 ID 为 2 的过程中, 刚执行到(1), 这时, 有另一个事务 ID 为 3 往这个表里插入了一条数据; 第三个事务 ID 为 3;
start transaction; insert into yang values(NULL, tian commit;
这时表中的数据如下:
然后接着执行事务 2 中的 (2), 由于 id= 4 的数据的创建时间(事务 ID 为 3), 执行当前事务的 ID 为 2, 而 InnoDB 只会查找事务 ID 小于等于当前事务 ID 的数据行, 所以 id= 4 的数据行并不会在执行事务 2 中的(2) 被检索出来, 在事务 2 中的两条 select 语句检索出来的数据如下:
假设 2
假设在执行这个事务 ID 为 2 的过程中, 刚执行到(1), 假设事务执行完事务 3 后,接着又执行了事务 4;
第四个事务:
start transaction; delete from yang where id=1; commit;
此时数据库中的表如下:
接着执行事务 ID 为 2 的事务 (2), 根据 SELECT 检索条件可以知道, 它会检索创建时间(创建事务的 ID) 小于当前事务 ID 的行和删除时间 (删除事务的 ID) 大于当前事务的行, 而 id= 4 的行上面已经说过, 而 id= 1 的行由于删除时间 (删除事务的 ID) 大于当前事务的 ID, 所以事务 2 的(2)select * from yang 也会把 id= 1 的数据检索出来. 所以, 事务 2 中的两条 select 语句检索出来的数据都如下:
UPDATE
InnoDB 执行 UPDATE,实际上是新插入了一行记录,并保存其创建时间为当前事务的 ID,同时保存当前事务 ID 到要 UPDATE 的行的删除时间。
假设 3:
假设在执行完事务 2 的 (1) 后又执行, 其它用户执行了事务 3,4, 这时,又有一个用户对这张表执行了 UPDATE 操作:
第 5 个事务:
start transaction; update yang set name= Long where id=2; commit;
根据 update 的更新原则: 会生成新的一行, 并在原来要修改的列的删除时间列上添加本事务 ID, 得到表如下:
继续执行事务 2 的(2), 根据 select 语句的检索条件, 得到下表:
还是和事务 2 中(1)select 得到相同的结果.
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注丸趣 TV 行业资讯频道,感谢您对丸趣 TV 的支持。