☞ 免费CSDN资料帮下服务 | 免费加群 ☜

90% 的程序员都认为 innodb 是行级锁,但实际上使用不当,它也是表级锁!

看过我博客的网友都知道,我之前写过一篇文章《InnoDB 的 select 行锁还是表锁?》。拯救过不少人,今天我们再来一次大拯救!

最近生产上的 MySQL 数据库,是不是的就来一次 DeadLock,其中我做了故障排查,昨天做了相关的升级,导致昨天非常的忙,很多网友加我好友,都没有及时回应,直到晚上升级结束,我在群里做了相关的解释!

截了一段错误日志信息如下:

其中涉及到的更新语句如下:

很奇妙吧,执行一条 update sql 竟然会有死锁?

具体死锁的提前是 i_pay_record 表中的 order_id 字段有索引。

下面我们通过新建一张表 xttblog,来说明问题。

当我们执行下面的 update 语句时,就有可能发生死锁!

mysql 的事务支持与存储引擎有关,MyISAM 不支持事务,INNODB 支持事务,更新时可能采用的是行级锁,也可能是表级锁。我们这里采用的是 INNODB 做存储引擎,意味着会将 update 语句做为一个事务来处理。前面的文章中我提到了行级锁必须建立在索引的基础上,上面的更新语句用到了索引 idx_1,所以这里肯定会加上行级锁。

行级锁并不是直接锁记录,而是锁索引(前面的文章也解释过)。

如果一条 SQL 语句用到了主键索引,mysql 会锁住主键索引;如果一条语句操作了非主键索引,mysql 会先锁住非主键索引,再锁定主键索引。

这个 update 语句会执行以下步骤:

  1. 由于用到了非主键索引,首先需要获取 idx_1 上的行级锁

  2. 紧接着根据主键进行更新,所以需要获取主键上的行级锁

  3. 更新完毕后,提交,并释放所有锁

如果在步骤 1 和 2 之间突然插入一条语句:update xttblog …..where id=? and user_id=? 这条语句,那么会先锁住主键索引,然后锁住 idx_1。

这时,悲剧就发生了!

一条语句获取了 idx_1 上的锁,等待主键索引上的锁;另一条语句获取了主键上的锁,等待 idx_1 上的锁,这样就出现了死锁。

很惊奇吧,其实一点也不奇怪,只要你了解了 MySQL 的一些底层设计原理!

那么发生这种问题,有解决方案吗?

当然有了,要不然我写这篇文章干什么?

解决方案,最笨最靠谱的做法就是:先获取需要更新的记录的主键,然后再逐条更新!

这样就可以解决问题了,但是这个解决方案与先前的更新语句不一样,先前的更新语句对所有记录的更新在一个事务中,采用循环更新后并不在同一个事务中,所以在 for 循环外面还得开一个事务。

在采用 INNODB 的 MySQL 中,更新操作默认会加行级锁,行级锁是基于索引的,在分析死锁之前需要查询一下 mysql 的执行计划,看看是否用到了索引,用到了哪个索引,对于没有用索引的操作会采用表级锁。如果操作用到了主键索引会先在主键索引上加锁,然后在其他索引上加锁,否则加锁顺序相反。在并发度高的应用中,批量更新一定要带上记录的主键,优先获取主键上的锁,这样可以减少死锁的发生。

不是说 update 不会发生死锁,而是你的程序没遇到高并发而已!关于死锁的故障分析排查,我们以后继续!

10T技术资源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,GO等等。在公众号内回复对应关键字或框架名字 ,即可免费获取!!

你再主动一点点 fbf3271f8b1ab6b46993f898bf588c75.gif 我们就有故事了

1. mysql 锁介绍表锁:锁住整张表表级别的锁定是 MySQL 各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次 将整个表锁定,所以可以很好的避免困扰我们的 死锁 问题。 当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也 最高,致使并大度大打折扣。行锁:锁住一行或者多行如果数据库表没有加索引,那么更新操作的时候 锁住整张表,也就是所谓的表级锁;如果有索引,并且查询条件中也带有这些字段,那么就 mysql 主键 设置成auto_increment时,进行并发性能测试出现 主键 重复Duplicate entry ‘xxx‘ for key ‘PRIMARY‘解决方法:在my.cnf的[ mysql d]片段中添加设置innodb_autoinc_lock_mode=0同时注意调大jdbc的活跃链接数,如设置jdbc.maxActive=300,因为设置innodb_autoinc_lock_mod... 为什么你的insert就 死锁 了一、前言本以为只需要系统学习一个较完全的逻辑,但是实际牵扯很多innodb锁相关知识及加锁方式。我好像并没有那么大的能耐,把各种场景的加锁过程一一列举并加之分析;亦没有太多的精力验证网上的言论的准确性。只好根据现在了解的内容,参考官方文档,说说自己当前的理解。本文仅供参考,如有误导,概不负责。二、现场状态不同的 mysql 版本,不同的参数设置,都可能对加锁过程有影响。分... 因为是边扫描边加锁,这里就存在一个顺序问题,假如线程A对a b c d e五条数据边扫描边加X锁,而同时线程B对 e f g h a五条数据也边扫描边加X锁,明显的,这就 存在一个问题,在线程A对e加锁时,线程B已经对e加锁了,所以线程A 等待线程B释放锁,而线程B对a加锁时,线程A也对a加锁了,所以线程B就 等待线程A释放锁,最终结果是,互相循环等待造成 死锁 。InnoDB行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。 来源:公众号「神谕的暗影长廊」在异步或半同步的复制结构中,从库出现延迟是一件十分正常的事。虽出现延迟正常,但是否需要关注,则一般是由业务来评估。如:从库上有需要较高一致性的读业务,并且要... 背景知识: MySQL 有三种锁的级别:页级、表级、行级。 MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁;InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。 MySQL 这3种锁的特性可大致归纳如 阅读本文约需要5分钟大家好,我是你们的导师,经常看我朋友圈的同学应该知道,我每天 在微信上给大家免费提供以下服务!1、长期为你提供最优质的学习资源!2、给你解决技术问题!3、每天在朋友圈里分享优质的技术文章!4、每周1、3、5送纸质书籍免费送给大家,每年至少送书800本书!5、为大家推荐靠谱的就业单位!请注意!我上面说的5点全部都是免费的!全网你应该找不到第二家吧!当然,大家在... 更改 mysql 配置如下:# Uncomment the following if you are using InnoDB tables#innodb_data_home_dir = /var/lib/ mysql /innodb_data_file_path = ibdata1:50M:autoextend#innodb_log_group_home_dir = /var/lib/ mysql /#in... 这个问题处理起来还是比较简单,但是背后还是有很多可以深挖的地方,本文主要使用的代码是5.7.22,对于semi update 下row locks不准的情况在8.0.28 也测试了,依旧存在这个问题。另外在8.0中热点锁LOCK_SYS视乎做了拆分,也许情况 好一些,随后也可以学习下这部分内容,看看官方如何拆锁的。... 转载 https://blog.csdn.net/e421083458/article/details/19907097 Analyze Table MySQL 的Optimizer(优化元件)在优化SQL 语句 时,首先需要收集一些相关信息,其中就包括表的cardinality(可以翻译为“散列程度”),它表示某个索引对应的列包含多少个不同的值——如果cardinality大大少于数据的实际散列程度,那么索引就基本失效了。 我们可以使用SHOW INDEX 语句 来查看索引的散列程度: SHOW INDEX FR 在做客户关系管理系统的时候遇到联表查询,速度特别 ,导致页面加载时间过长而出现错误。在上网查询后发现建立索引可以优化查询 在没有建立索引的时候 select c.*,s.* from crm_cu_re c join crm_cu_info s on c.CUS_MAIN_ID=s.CUS_MAIN_ID) (526 row(s) returned) Total Time 通过以上的情况可以看出, MySQL 默认的查询(没有where条件),不一定使用 主键 ,由于 MySQL 的每一条简单查询只应用一个索引,所以,这个时候使用order by 主键 主键 的索引功能失效。1、 MySQL 每天一条简单 语句 只应用一个索引,所以order by的字段要在索引之中,并且和where条件可以合并成组合索引。为了进一步确定,再对下面的sql 语句 执行查询计划:发现使用where条件后,索引变成了 主键 。今天遇到个奇葩的问题,应用 主键 排序速度奇 无比,经过不懈的努力,终于找到了问题的原因。 近期公司的新项目的测试环境的 mysql 环境,一条sql根据id列( 主键 )更新一条记录,速度奇 .找不到原因,请大家帮忙分析下.硬件ibm x3550 8g内存 mysql 5.6.21 x64 单机基本上没有负载,表的情况,大概只有不到100行的数据.这个是当时执行的sqlid为自增长的 主键 update t_customer_info set update _time='2014-11-17 12:...