mysql锁技术讨论

mysql 常见锁问题分析

1 参考资料

2 要明确的概念

  • 不可重复读和幻读的区别
  • 快照读和当前读
  • 事务的隔离级别
  • record lock、gap lock、next-key lock

2.1 不可重复读和幻读的区别

select数据的不变性可以细分成2部分

  • 第一部分就是:对原有数据的不可修改性,如update delete,通过行锁锁住记录就可以实现不可修改
  • 另一部分就是:对于新增数据的限制,这时候就不能通过行锁来解决了,这时候就需要通过gap lock来解决

如果仅仅满足了第一部分可以叫可重复读,如果也满足了第二部分就算是解决了幻读的问题。

而目前mysql的innodb数据库引擎实现的Repeatable reads不仅仅解决了上述的第一部分也解决第二部分,即Repeatable reads级别下已经解决了幻读问题。

2.2 快照读和当前读

快照读: 如普通的select * from t where id>=6;采用MVCC(多版本并发控制)仅仅读取该事务号及其之前的数据

当前读:如select * from t where id>=6 for update;读取的是最新提交的事务号及其之前的数据

2.3 事务的隔离级别

Read committed 的隔离级别:只能读到别人已提交的数据,未提交的数据读不到,RC的隔离级别存在不可重复读和幻读的现象,即在同一个事务内,第一次select查询出一定结果后,别的客户端此时又修改了源数据和提交了新的数据,第二次select是可以查出修改后的数据和新提交的数据的,这就导致了和第一次select的数据不一致的问题

Repeatable reads 的隔离级别:比起Read committed,解决了不可重复读的现象,而mysql的innodb数据库引擎实现的Repeatable reads也解决了幻读问题。

  • 对于快照读中的幻读(即select * from t where id>=6出现的幻读)采用的解决方式是采用MVCC(多版本并发控制)
  • 对于当前读中的幻读(即select * from t where id>=6 for update出现的幻读)采用的解决方式是gap lock

3 问题分析

如下的一个事务并发执行

start transaction;
DELETE FROM t WHERE id =6;
INSERT INTO t VALUES(6);
commit;

就隔离级别和id唯一索引、id非唯一索引组合等情况展开分析以下内容:

  • 使用了什么锁?阻塞情况?
  • 是否会出现死锁?

3.1 Read committed和唯一索引id

3.2 Read committed和非唯一索引id

3.3 Repeatable reads和唯一索引id

创建表的sql:

create table m (
    id int ,
    primary key (id)
);

填充数据 1、2、6、8

insert into m values(1),(2),(6),(8);

步骤1:客户端A

start transaction;
delete from m where id =6;

步骤2:客户端B

start transaction;
delete from m where id =6;

步骤3:客户端A

insert into m value(6);

步骤4:客户端B

insert into m value(6);

3.3.1 删除一个已存在的值

其中delete from m where id =6语句会对索引中id=6的记录加上next-key lock,但是由于where id=6的查询条件结果是确定的,即不会出现幻读的情况,所以仅仅对id=6的记录加上一个record lock即可,即由next-key lock降级到了record lock。

所以当客户端A执行完毕步骤1后,客户端B执行步骤2的时候,由于已经存在了record lock,所以客户端B会被阻塞,等待客户端A的record lock的释放,现象如下:

3.3.2 删除一个不存在的值

上述的id=6全部换成id=5,即客户端A执行delete from m where id=5;由于记录不存在,所以只会在索引(2,6)区间中加上gap lock。此时如果客户端B也同样执行delete from m where id=5,由于记录不存在,也只会在索引(2,6)区间中加上gap lock,这两个gap lock之间不冲突,可以同时存在。

此时客户端执行insert into m value(5),因为insert语句会添加一个 insert intention gap lock(见官方文档insert intention gap lock),其中这个锁和gap lock是可以冲突的,此时插入的数值5刚好在上述客户端B创建的gap lock锁定的区间中,所以此时客户端A是要等待客户端B释放gap lock的,即被阻塞了

此时客户端B同样执行insert into m value(5),也会因为客户端A创建的gap lock而造成阻塞,此时客户端A、B相互阻塞造成死锁,现象如下

发生死锁后,innode引擎自动检测到死锁,会让一个进行释放,另一个得到执行

3.4 Repeatable reads和非唯一索引id

创建表的sql:

create table t (
    id int ,
    key (id)
);

填充数据 1、2、6、8

insert into t values(1),(2),(6),(8);

步骤1:客户端A

start transaction;
delete from t where id =6;

步骤2:客户端B

start transaction;
delete from t where id =6;

步骤3:客户端A

insert into t value(6);

步骤4:客户端B

insert into t value(6);

3.4.1 删除一个已存在的值

其中delete from t where id =6语句会对索引中id=6的记录加上next-key lock,即id=6的记录本身加上record lock,同时(2,6)、(6,8) 这两个区间会加上gap lock。

所以当客户端A执行完毕步骤1后,客户端B执行步骤2的时候,由于已经存在了record lock,所以客户端B会被阻塞,等待record lock的释放,现象如下:

3.4.2 删除一个不存在的值

假如上述的id=6全部换成id=5,执行 delete from t where id =5的话,即delete 一个不存在的值,则只会对索引的(2,6)区间加上gap lock。客户端B就不会阻塞,同样的在索引(2,6)区间加上gap lock,gap lock之间不冲突的,即这时的客户端B不会阻塞。

这时客户端A执行 insert into t value(5)会阻塞,因为insert语句会添加一个 insert intention gap lock(见官方文档insert intention gap lock),其中这个锁和gap lock是可以冲突的,此时插入的数值5刚好在上述客户端B创建的gap lock锁定的区间中,所以此时客户端A是要等待客户端B释放gap lock的,即被阻塞了

而客户端A执行的insert into t value(5)所加入的insert intention gap lock是不会和自己创建的gap lock冲突的,即如果没有其他gap lock的话,客户端A往自己创建的gap lock区间中insert值是不被阻塞的

假如此时客户端B同样执行insert into t value(5)操作,则会因为客户端A创建的gap lock而等待,此时客户端A B在相互等待对方释放gap lock,造成死锁,现象如下:

发生死锁后,innode引擎自动检测到死锁,会让一个进行释放,另一个得到执行

4 案例演示当前读和快照读

创建表的sql:

create table t (
    id int ,
    key (id)
);

填充数据 1、2、6、8

insert into t values(1),(2),(6),(8);

步骤1:客户端A

start transaction;
select * from t where id>=6;

步骤2:客户端B

start transaction;
insert into t value(10);
commit;

步骤3:客户端A

select * from t where id>=6;
select * from t where id>=6 for update;

步骤3中是第一个select是看不到客户端B新增的数据的,因为他是快照读,读取的是该事务号及其之前的数据

步骤3中的第二个select是可以看到客户端B新增的数据的,因为它是当前读,读取的是最新提交的事务号及其之前的数据

现象如下:

时间: 2024-08-11 06:23:14

mysql锁技术讨论的相关文章

MySQL DBA技术难度低为什么工资比Oracle高?

编辑手记:前几天在知乎上出现了一个很热的帖子,话题是"MySQL DBA技术难度低为什么工资比oracle高?",这个话题很快引起了热烈的讨论.从回帖的情况来看,大部分人几乎都默认了MySQL DBA工资的确高这个事实,那么原因是什么,我们节选MySQL专家刘伟的回帖跟大家分享. 以下是他回帖的原文: 主要有以下两个原因: 1.市场供需关系 2.技术要求相对高 这两个因素一直没有得到改善,导致现在市场的行情是:招MySQL DBA难,招称心的MySQL DBA就更难. 先说一个工资议价

【JAVA秒会技术之玩转SQL】MySQL优化技术(二)

MySQL优化技术(二) [前文连接]MySQL优化技术(一) (五)常用SQL优化 1.默认情况,在使用group by 分组查询时,会先分组,其后还会默认对组内其他条件进行默认的排序,可能会降低速度.这与在查询中指定order by col1, col2类似. 如果查询中包括group by但用户想要避免排序结果的消耗,则可以使用order by null禁止排序. 例子:   2.尽量使用左连接(或右连接)来替代普通多表联查.因为使用JOIN,MySQL不需要在内存中创建临时表.    s

mysql 5 mysql 5 技术内幕

mysql 5 mysql 5 技术内幕: http://www.kitebird.com/mysql-book/4ed.php

Informix数据库锁技术

INFORMIX使用锁技术解决在多用户访问数据库情况下,对同一对象访问的并发控制问题.INFORMIX 支持复杂的.可伸缩性的锁技术. 锁的类型 INFORMIX有三种不同类型的锁.它们在不同的情况下使用. 1. SHARED锁 SHARED锁只保留对象的可读性.当锁存在时,对象不能改变.多个程序可对同个对象加SHARED锁. 2. EXCLUSIVE锁 只能使单个程序使用.在程序要改变对象时使用.当其他锁存在时,EXCLUSIVE锁不能使用.当使用了E XCLUSIVE 锁后,其他锁不能用于同

MySQL分页技术、6种分页方法总结

  这篇文章主要介绍了MySQL分页技术.6种分页方法总结,本文总结了6种分页的方法并分别一一讲解它们的特点,需要的朋友可以参考下 概述 有朋友问: MySQL的分页似乎一直是个问题,有什么优化方法吗? 网上看到赶集网XX推荐了一些分页方法,但似乎不太可行,你能点评一下吗? 方法总结 方法1: 直接使用数据库提供的SQL语句 语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 LIMIT M,N 适应场景: 适用于数据量较少的情况(元组百/千级) 原因/缺点: 全表扫描

spring mvc-java web前端实现技术讨论

问题描述 java web前端实现技术讨论 做过java web项目开发的人都知道struts2和spring mvc,这两者都是java前端的mvc架构,页面利用丰富的struts和spring标签,通过框架提供的多种封装技术方便快捷的跟action或者Controller进行交互,从而简化页面的功能实现.另一种页面实现则是采用javascript+html+css,不使用框架提供的标签或者其它功能,而是通过ajax或者其它方式调用action或者Controller的代码.对于这两种方式(或

【JAVA秒会技术之玩转SQL】MySQL优化技术(一)

MySQL优化技术(一)         开发的路上,总会碰到一些老系统,越用越慢."慢"的原因也许有很多,但是,博主个人觉得,数据库的设计和sql语句写的好坏,对系统效率的影响是最直接,最显而易见的!所以,学习一下MySQL的优化,还是很有必要的.当然,博主能力有限,没那么多经验,更多的是"道听途说"和"纸上谈兵".如有不正之处,望大神开后给予指正,不胜感激! (一)MySQL优化技术概述 ①表的设计合理化(符合3NF,即符合"三范式

Yii+MYSQL锁表防止并发情况下重复数据的方法_php实例

本文实例讲述了Yii+MYSQL锁表防止并发情况下重复数据的方法.分享给大家供大家参考,具体如下: lock table 读锁定 如果一个线程获得在一个表上的read锁,那么该线程和所有其他线程只能从表中读数据,不能进行任何写操作. lock tables user read;//读锁定表 unlock tables;//解锁 lock tables user read local;//本地读锁定表,其他线程的insert未被阻塞,update操作被阻塞 lock table 写锁定 如果一个线

lattices-有研究加密算法的技术讨论群吗

问题描述 有研究加密算法的技术讨论群吗 最近在研究lattices加密算法 有类似的组织根据地吗 求大大们拖走 我的QQ451800977