Mysql查询语句使用select.. for update导致的数据库死锁分析

近期有一个业务需求,多台机器需要同时从Mysql一个表里查询数据并做后续业务逻辑,为了防止多台机器同时拿到一样的数据,每台机器需要在获取时锁住获取数据的数据段,保证多台机器不拿到相同的数据。

我们Mysql的存储引擎是innodb,支持行锁。解决同时拿数据的方法有很多,为了更加简单,不增加其他表和服务器的情况下,我们考虑采用select... for update的方式,这样X锁锁住查询的数据段,表里其他数据没有锁,其他业务逻辑还是可以操作。

这样一台服务器比如select .. for update limit 0,30时,其他服务器执行同样sql语句会自动等待释放锁,等待前一台服务器锁释放后,该台服务器就能查询下一个30条数据。如果达到更智能,oracle支持for update skip locked跳过锁区域,这样能不等待马上查询出下一个30条记录。

这里还是需要说mysql for update导致的死锁。

经过分析,mysql的innodb存储引擎实务锁虽然是锁行,但它内部是锁索引的,根据where条件和select的值是否只有主键或非主键索引来判断怎么锁,比如只有主键,则锁主键索引,如果只有非主键,则锁非主键索引,如果主键非主键都有,则内部会按照顺序锁。但同样的select .. for update语句怎么就死锁了呢?同样的sql语句查询条件和结果顺序都一致,按理不会导致一个锁了主键索引,等待锁非主键索引,另外一个锁了非主键索引,等待主键索引导致的死锁。

最后经过分析,发现是for update的sql语句,和另外一个update语句导致的死锁。

比如有60条数据,select .. for update查询第31-60条数据,update在更新1-10条数据,按照innodb存储引擎的行锁原理,应该不会导致不同行的锁导致的互相等待。开始以为是行锁在数据量较大情况下,会锁数据块。导致一个段的数据被锁住,但经过大量数据测试,发现感觉把整个表都锁住了,但实际不是。

家里电脑没有环境,改天用公司电脑描述具体场景。

时间: 2024-10-11 14:08:05

Mysql查询语句使用select.. for update导致的数据库死锁分析的相关文章

mysql查询语句

mysql查询语句常用SELECT命令打印当前的日期和时间select now();打印当前的日期select curdate();打印当前时间select curtime();查看当前版本select version();打印当前用户select user();查看当前数据库实例select database();查看系统中可用的变量show variables;查看系统中全局变量show global variables;一般查询系统可用变量或是全局变量都是通过like的方式来进行查询的,因

MySQL 查询语句SELECT和数据条件过滤

MySQL 查询语句SELECT ,主要是用 * 表示任意字段,也可以写id,name,content 等,数据条件过滤主要是between,and,or ,WHERE,in,like,limit,not in等. 1,查询语句SELECT的用法 select * from biao 2,查询语句数据条件的用法where 条件的开始and 并联关系or 或者的关系between 两者之间like 模糊查询limit 限制查询的条数in 在什么里面not in 不在什么里面 文章来自(www.dc

[学习记录]MySQL之初级查询语句(select,where)

标准的查询语句如下 select 列名1,列名2,列名3 from 表名 该语句将返回该表中对应列的所有行 如果想要检索表中所有列则可以使用* select * from 表名a 由于表中非码属性允许重复,所以发现检索结果中有重复项,可以通过distinct过滤 select distinct 列名 from 表名f 如果只关心检索结果的前若干行,可以使用limit子句 select 列名 from 表名 limit a,b 意思为输出从第a行开始一共b行元素,如果不提供a则从第1行开始 如果需

Mysql 原生语句中save or update 的各种写法

Mysql 原生语句中save or update 的各种写法 背景 ??在平常的开发中,经常碰到这种更新数据的场景:先判断某一数据在库表中是否存在,存在则update,不存在则insert. 如果使用Hibernate,它自带saverOrUpdate方法,用起来很方便,但如使用原生sql语句呢? ??新手最常见的写法是,先通过select语句查询记录是否存在,存在则使用update语句更新,不存在则使用insert语句插入. 但是这样做明显不够优雅,存在几个问题: 为了执行一次更新操作,却在

MySQL 查询语句使用进阶

MySQL 查询语句使用进阶 =============================================================================== 概述: =============================================================================== 练习: 练习1  首先导入hellodb.sql的脚本文件,查询其数据库和表如下: [[email protected] ~]# mysql 

【个人笔记】MySQL查询语句

最近学习了MySQL,分享一点其中查询语句的使用 语法:select  显示的内容  from  查询的范围   where   查询的条件 (显示全部内容用'*'号) 一.as 别名(可省略as) 例:select   stuname  as  '学生姓名'   form   t_student   where  stuname='张三',此句的意思是将学生表中姓名为'张三'的学生筛选出来,并将选出来的列重新命名为'学生姓名'. 二.distinct  筛选重复的数据 三.筛选条件有: and

直接从命令行获取MySQL查询语句结果

如果你需要直接从命令行获取MySQL查询语句结果,那么你可以使用-B和-N这两个参数来达到目的. 例:获取MySQL用户数. [[email protected] ~]# mysql -BN -uroot -predhat mysql -e 'select count(*) from user' 6 [[email protected] ~]# -B参数:去掉边框 -N参数:只显示结果

mysql学习——mysql查询语句综合练习

练习一: 设有成绩表stu如下: 姓名 科目 成绩 张三 数学 90 张三 语文 50 张三 地理 40 李四 语文 55 李四 政治 45 王五 政治 30 王五 数学 70 试查询两门及两门以上不及格同学的平均分 解答如下 1.创建数据表 create table stu(id int primary key auto_increment,name char(3) not null default'',subject char(3) not null default'',score deci

MySQL 查询语句执行顺序

Mysql查询语句时候一共分为11步,其中每一个操作都会产生一张虚拟的表,这个虚拟的表作为一个处理的输入,只是这些虚拟的表对用户来说是透明的,但是只有最后一个虚拟的表才会被作为结果返回. 语句执行顺序 : 顺序 名称 内容 1 SELECT 命令发起 2 * 或 AVG(字段)等 查询内容 3 FROM 查询位置 4 WHERE 条件查询 5 GROUP BY 分组 6 HAVING 筛选 7 ORDER BY (ASC/DESC) 排序 8 LIMIT 限制结果数 1.单表查询 查询指定的列