首页 数据库 mysql教程 Mysql 数据库死锁过程分析

Mysql 数据库死锁过程分析

Jun 01, 2016 am 09:57 AM
mysql 死锁

近期有一个业务需求,多台机器需要同时从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非select数据的sql语句导致的死锁。

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

下面举几个例子说明:

数据从id =400000的数据开始,IsSuccess和GetTime字段都为0,现在如果400000数据的IsSuccess为1了。执行下面两条sql.

<code class="sql">-- 1:
set autocommit=0;
begin;
select * from table1 where getTime </code>
登录后复制
登录后复制

第一条sql语句先不commit,则第二条sql语句将只能等待,因此第二条sql语句把IsSuccess修改为0,IsSuccess非主键索引锁了值为0的索引数据,第二条sql语句将无法把数据更新到被锁的行里。

再执行下面的sql语句

<code class="sql">-- 1:
set autocommit=0;
begin;
select * from table1 where getTime </code>
登录后复制
登录后复制

这样第二条sql语句将可以执行。因为IsSuccess=2的索引段没有被锁。

上面的例子知道了锁索引段后还比较容易看懂,下面就奇葩一点:

先把id =400000数据的GetTime修改为1,IsSuccess=0,然后一次执行sql:

<code class="sql">-- 1:
set autocommit=0;
begin;
update ctripticketchangeresultdata a set issuccess=1 where id =400000;
commit;
-- 2:
select * from table1 where getTime </code>
登录后复制

第1个sql先不commit,按照道理只会锁40000这行记录,第二个sql执行,按照道理只能查询从400001记录的30条记录,但第二个sql语句会阻塞等待。

原因是第一个sql语句还没有commit也没有rollback,因此它先锁主键索引,再锁IsSuccess的非主键索引,第二个sql语句由于where里要判断IsSuccess字段的值,由于400000这条数据以前的IsSuccess是0,现在更新为1还不确定,可能会回滚,因此sql2需要等待确定400000这条数据的IsSuccess是否被修改。sql2的sql语句因为判断了GetTime

因此如果根据业务场景,可以把sql2语句的IsSuccess条件取消掉,并且这里GetTime查询条件由GetTime

GetTime用范围查询导致的锁影响经过分析,还不是间隙锁的问题,感觉应该是用范围作为条件,所有从第0行开始的所有查找范围都会被锁住。 比如这里更新400000会被阻塞,但更新400031不会被阻塞。

我们项目出现死锁,就是这个原理,一条sql语句先锁主键索引,再锁非主键索引;另外一条sql语句先锁非主键索引,再锁主键索引。虽然两个sql语句期望锁的数据行不一样,但两个sql语句查询或更新的条件或结果字段如果有相同列,则可能会导致互相等待对方锁,2个sql语句即引起了死锁。

个人总结一下innodb存储引擎下的锁的分析,可能会有问题:

1、更新或查询for update的时候,会在where条件中开始为每个字段判断是否有锁,如果有锁就会等待,因为如果有锁,那这个字段的值不确定,只能等待锁commit或rollback后数据确定后再查询。

2、另外还和order by有关系,因为可能前面数据有锁,但从后面查询一个范围就可以查询。

3、另外limit也有关系,比如limit 20,30从第20条记录取30行数据,但第一行数据如果被锁,因为不确定回滚还是提交,也会锁等待。

ps:mysql使用kill命令解决死锁问题,杀死某条正在执行的sql语句

使用mysql运行某些语句时,会因数据量太大而导致死锁,没有反映。这个时候,就需要kill掉某个正在消耗资源的query语句即可, KILL命令的语法格式如下:

<code class="sql">KILL [CONNECTION | QUERY] thread_id</code>
登录后复制

每个与mysqld的连接都在一个独立的线程里运行,您可以使用SHOW PROCESSLIST语句查看哪些线程正在运行,并使用KILL thread_id语句终止一个线程。

KILL允许自选的CONNECTION或QUERY修改符:KILL CONNECTION与不含修改符的KILL一样:它会终止与给定的thread_id有关的连接。KILL QUERY会终止连接当前正在执行的语句,但是会保持连接的原状。

如果您拥有PROCESS权限,则您可以查看所有线程。如果您拥有超级管理员权限,您可以终止所有线程和语句。否则,您只能查看和终止您自己的线程和语句。您也可以使用mysqladmin processlist和mysqladmin kill命令来检查和终止线程。

首先登录mysql,然后使用: show processlist; 查看当前mysql中各个线程状态。

<code class="sql">mysql> show processlist;
+------+------+----------------------+----------------+---------+-------+-----------+--------------------- 
| Id  | User | Host         | db       | Command | Time | State   | Info
+------+------+----------------------+----------------+---------+-------+-----------+--------------------- 
| 7028 | root | ucap-devgroup:53396 | platform    | Sleep  | 19553 |      | NULL
| 8352 | root | ucap-devgroup:54794 | platform    | Sleep  | 4245 |      | NULL
| 8353 | root | ucap-devgroup:54795 | platform    | Sleep  |   3 |      | NULL
| 8358 | root | ucap-devgroup:62605 | platform    | query  | 4156 | updating | update t_shop set |
</code>
登录后复制

以上显示出当前正在执行的sql语句列表,找到消耗资源最大的那条语句对应的id.

然后运行kill命令,命令格式如下:

kill id;
-- 示例:
 kill 8358

杀掉即可。

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

phpmyadmin怎么打开 phpmyadmin怎么打开 Apr 10, 2025 pm 10:51 PM

可以通过以下步骤打开 phpMyAdmin:1. 登录网站控制面板;2. 找到并点击 phpMyAdmin 图标;3. 输入 MySQL 凭据;4. 点击 "登录"。

MySQL:世界上最受欢迎的数据库的简介 MySQL:世界上最受欢迎的数据库的简介 Apr 12, 2025 am 12:18 AM

MySQL是一种开源的关系型数据库管理系统,主要用于快速、可靠地存储和检索数据。其工作原理包括客户端请求、查询解析、执行查询和返回结果。使用示例包括创建表、插入和查询数据,以及高级功能如JOIN操作。常见错误涉及SQL语法、数据类型和权限问题,优化建议包括使用索引、优化查询和分表分区。

redis怎么使用单线程 redis怎么使用单线程 Apr 10, 2025 pm 07:12 PM

Redis 使用单线程架构,以提供高性能、简单性和一致性。它利用 I/O 多路复用、事件循环、非阻塞 I/O 和共享内存来提高并发性,但同时存在并发性受限、单点故障和不适合写密集型工作负载的局限性。

为什么要使用mysql?利益和优势 为什么要使用mysql?利益和优势 Apr 12, 2025 am 12:17 AM

选择MySQL的原因是其性能、可靠性、易用性和社区支持。1.MySQL提供高效的数据存储和检索功能,支持多种数据类型和高级查询操作。2.采用客户端-服务器架构和多种存储引擎,支持事务和查询优化。3.易于使用,支持多种操作系统和编程语言。4.拥有强大的社区支持,提供丰富的资源和解决方案。

MySQL的位置:数据库和编程 MySQL的位置:数据库和编程 Apr 13, 2025 am 12:18 AM

MySQL在数据库和编程中的地位非常重要,它是一个开源的关系型数据库管理系统,广泛应用于各种应用场景。1)MySQL提供高效的数据存储、组织和检索功能,支持Web、移动和企业级系统。2)它使用客户端-服务器架构,支持多种存储引擎和索引优化。3)基本用法包括创建表和插入数据,高级用法涉及多表JOIN和复杂查询。4)常见问题如SQL语法错误和性能问题可以通过EXPLAIN命令和慢查询日志调试。5)性能优化方法包括合理使用索引、优化查询和使用缓存,最佳实践包括使用事务和PreparedStatemen

使用 Redis Exporter 服务监控 Redis Droplet 使用 Redis Exporter 服务监控 Redis Droplet Apr 10, 2025 pm 01:36 PM

有效监控 Redis 数据库对于保持最佳性能、识别潜在瓶颈和确保整体系统可靠性至关重要。 Redis Exporter Service 是一个强大的实用程序,旨在使用 Prometheus 监控 Redis 数据库。 本教程将指导您完成 Redis Exporter Service 的完整设置和配置,确保您无缝建立监控解决方案。通过学习本教程,您将实现完全可操作的监控设置

sql数据库错误怎么查看 sql数据库错误怎么查看 Apr 10, 2025 pm 12:09 PM

SQL数据库错误查看方法有:1. 直接查看错误消息;2. 使用SHOW ERRORS和SHOW WARNINGS命令;3. 访问错误日志;4. 使用错误代码查找错误原因;5. 检查数据库连接和查询语法;6. 使用调试工具。

apache怎么连接数据库 apache怎么连接数据库 Apr 13, 2025 pm 01:03 PM

Apache 连接数据库需要以下步骤:安装数据库驱动程序。配置 web.xml 文件以创建连接池。创建 JDBC 数据源,指定连接设置。从 Java 代码中使用 JDBC API 访问数据库,包括获取连接、创建语句、绑定参数、执行查询或更新以及处理结果。

See all articles