博客
关于我
Mysql-解决幻读
阅读量:436 次
发布时间:2019-03-06

本文共 1821 字,大约阅读时间需要 6 分钟。

2.MVCC和Next-key locks

2.1 MVCC(MultiVersion Concurrent Control)

2.1.1 机制

MVCC即多版本并发控制,是InnoDB自带的一种机制,其为表格添加了三个列,如下

DB_ROW_ID DB_ROLL_PTR DB_TRX_ID col1
隐藏的行id,当没有合适的列可以创建索引时,使用此列创建索引 回滚指针,指向Undo Log中的上一版本数据的地址 记录当前事务的id

其中DB_TRX_ID和DB_ROLL_PTR是关键,下面举例说明,

当一个事务A开启后,在RR隔离级别下,只在第一次调用select时会获得一个表格的Read View,其包括四个属性

  • trx_ids: 截至目前,系统活跃的事务版本号,包括自己
  • low_limit_id: 当前事务版本号+1
  • up_limit_id: 除本事务外,截至目前,活跃事务的最小版本号
  • creator_trx_id: 创建当前read view的事务版本号

那么在开启事务A后,执行

  • SELECT

    会根据Read View对数据进行过滤,其可以读取到的数据有如下部分

    • 本事务内添加的数据
    • 所有版本号小于up_limit_id的已提交事务的结果

    除上面提到的,都不可以select到,如trx_ids中除了当前事务号插入的数据,因为这些事务仍然活跃且未提交

  • 包括update、insert、delete,都会将对应数据行的DB_TRX_ID赋值为当前事务版本号

2.1.2 当前读和快照读

1)快照读

MVCC机制下,select读取数据是不需要加锁的,其读取的是快照中的数据,包含事务开启前的数据以及当前事务添加的数据

2)当前读

也即insert、update、delete这三种方式,其会对访问数据加锁

见下面例子

事务A 事务B
begin;
begin;
select * from test; 🎈
insert into test(id,name) values(3,'kk');
select * from test;与🎈处查询结果一致
commit;
insert into test(id,name) values(3,'kk'); 报错!因为此数值已经出现在表格中,但是由于查询时遵循MVCC的机制,因而不能查询出未提交事务的结果;如果在事务Bcommit之前发生,则会被阻塞
select * from test;//可以查询到事务B插入的值

从上可见,由于insert操作属于当前读,事务A在Bcommit前进行insert时,会被阻塞,但是select不会被阻塞

那么,在事务A中进行insert这个当前读操作就发生了幻读,因为这和select读取的结果不一致

2.2 Next-Key Locks

从MVCC的机制可知,其不能解决幻读,InnoDB引入了Next-Key Lock解决了此问题(关键在于上锁

2.2.1 Record Locks

锁定一个记录上的索引,而不是记录本身

2.2.2 Gap Locks

锁定索引之间的间隙

假设select * from test where id between 10 and 20 for update;

那么id从10到20的数据就会被锁住,尽管10-20之间可能没有数据

2.2.3 Next-Key Locks

首先会对指定的行的索引上锁,且会对索引之前所在的gap上锁

假设在事务A中执行select * from test where id=3 for update;且假设当前表格中有id为1,5,10

那么,有如下情况,如果id为

  • 主键(UNIQUE

    不会触发gap lock

  • 普通索引(UNUNIQUE

    会锁住id为(1,5]的区间

  • 不是索引

    那么会对(-∞,+∞)上锁

2.3 Serializable解决幻读

MySQL下的这个隔离级别解决幻读的方式很悲观,其会对事务中每条sql涉及到的资源进行上锁,这样就可以阻塞其他事务对数据的操作,从而使得事务可以串行化的执行

可见,这种方式的效率是很低的

一般情况下,在RR隔离级别时,可以通过使用Next-Key Locks的方式对敏感数据上锁,即可保证一定区域内幻读的解决

触发Next-Key Locks有select for update和当前读操作

# 参考

转载地址:http://kasyz.baihongyu.com/

你可能感兴趣的文章
mysql5.7性能调优my.ini
查看>>
MySQL5.7新增Performance Schema表
查看>>
Mysql5.7深入学习 1.MySQL 5.7 中的新增功能
查看>>
Webpack 之 basic chunk graph
查看>>
Mysql5.7版本单机版my.cnf配置文件
查看>>
mysql5.7的安装和Navicat的安装
查看>>
mysql5.7示例数据库_Linux MySQL5.7多实例数据库配置
查看>>
Mysql8 数据库安装及主从配置 | Spring Cloud 2
查看>>
mysql8 配置文件配置group 问题 sql语句group不能使用报错解决 mysql8.X版本的my.cnf配置文件 my.cnf文件 能够使用的my.cnf配置文件
查看>>
MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
查看>>
MYSQL8.0以上忘记root密码
查看>>
Mysql8.0以上重置初始密码的方法
查看>>
mysql8.0新特性-自增变量的持久化
查看>>
Mysql8.0注意url变更写法
查看>>
Mysql8.0的特性
查看>>
MySQL8修改密码报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
查看>>
MySQL8修改密码的方法
查看>>
Mysql8在Centos上安装后忘记root密码如何重新设置
查看>>
Mysql8在Windows上离线安装时忘记root密码
查看>>
MySQL8找不到my.ini配置文件以及报sql_mode=only_full_group_by解决方案
查看>>