最近在开发的时候,在mysql Innodb 引擎下,一条记录记录也能引起锁的事件。

场景描述

在项目压测的是,突然发现有类似以下的异常发生:

com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
at sun.reflect.GeneratedConstructorAccessor247.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
at com.mysql.jdbc.Util.getInstance(Util.java:381)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1045)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3491)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3423)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1936)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2060)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2542)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1734)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2019)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1937)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1922)

但代码里面明明只锁了一条记录,不存在多个资源的时候,死锁又是怎么来的呢。

例子

首先创建实验数据:

DROP TABLE IF EXISTS `account_info`;
CREATE TABLE `account_info` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`account` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
`current_amt` decimal(18,2) DEFAULT NULL,
PRIMARY KEY (`uid`),
UNIQUE KEY `idx_account` (`account`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; INSERT INTO `account_info` VALUES (1, 'tester', 1.00);

这里的是 uid 是主键, account 是唯一索引。

时间 Transaction1 Transaction2
T1 set autocommit=false;
begin;
T2 select * from account_info where uid = 1 for update;
T3 set autocommit=false;
begin;
T4 update account_info set current_amt = current_amt +1 where account = 'tester';
T5 update account_info set current_amt = current_amt +1 where account = 'tester';

在执行到T5的时候,mysql 返回了一下的异常:

1213 - Deadlock found when trying to get lock; try restarting transaction, Time: 0.000000s

What? 死锁? 锁一条记录也会死锁?

原理分析

在 mysql 的 innodb 引擎下,行级锁并不是直接锁记录,而是锁索引,如果一条 sql 语句用到了主键索引,mysql 会锁住主键索引;如果一条语句操作了非主键索引,mysql 会先锁住该非主键索引,再锁住主键索引。

例子

  • 新开一个session,执行一下语句
set autocommit=false;
begin;
select * from account_info where uid = 1 for update;
  • 然后再打开另外一个session,执行查看 innodb 事务
select * from information_schema.INNODB_TRX;

会出现一下内容摘要,其中 trx_rows_locked 内容是 1

trx_id trx_state trx_tables_locked trx_rows_locked trx_rows_modified trx_isolation_level
5831745 RUNNING 1 1 0 REPEATABLE READ
  • 把前面的 session 关闭后,再重新打开一个session执行一下语句
set autocommit=false;
begin;
select * from account_info where account = 'tester' for update;
  • 然后再打开另外一个session,执行查看 innodb 事务
select * from information_schema.INNODB_TRX;

会出现一下内容摘要,其中 trx_rows_locked 内容是 2

trx_id trx_state trx_tables_locked trx_rows_locked trx_rows_modified trx_isolation_level
5831748 RUNNING 1 2 0 REPEATABLE READ

会看到上面的例子,用主键索引加锁的时候,只会出现一把锁,若用非主键索引的时候,就出现了两把锁,这也是单条记录造成了死锁的原因。

微信关注我,发现更多java领域知识

mysql单记录也能造成的死锁的更多相关文章

  1. MySQL单表最大记录数不能超过多少?

    MySQL单表最大记录数不能超过多少? 很多人困惑这个问题.其实,MySQL本身并没有对单表最大记录数进行限制,这个数值取决于你的操作系统对单个文件的限制本身. 从性能角度来讲,MySQL单表数据不要 ...

  2. MySQL单表多字段模糊查询

    今天工作时遇到一个功能问题:就是输入关键字搜索的字段不只一个字段,比如 我输入: 超天才 ,需要检索出 包含这个关键字的 name . company.job等多个字段.在网上查询了一会就找到了答案. ...

  3. MySQL行(记录)的详细操作一 介绍 二 插入数据INSERT 三 更新数据UPDATE 四 删除数据DELETE 五 查询数据SELECT 六 权限管理

    MySQL行(记录)的详细操作 阅读目录 一 介绍 二 插入数据INSERT 三 更新数据UPDATE 四 删除数据DELETE 五 查询数据SELECT 六 权限管理 一 介绍 MySQL数据操作: ...

  4. python 3 mysql 单表查询

    python 3 mysql 单表查询 1.准备表 company.employee 员工id id int 姓名 emp_name varchar 性别 sex enum 年龄 age int 入职 ...

  5. day 37 MySQL行(记录)的详细操作

    MySQL行(记录)的详细操作   阅读目录 一 介绍 二 插入数据INSERT 三 更新数据UPDATE 四 删除数据DELETE 五 查询数据SELECT 六 权限管理 一 介绍 MySQL数据操 ...

  6. MySQL单表数据不超过500万:是经验数值,还是黄金铁律?

    今天,探讨一个有趣的话题:MySQL 单表数据达到多少时才需要考虑分库分表?有人说 2000 万行,也有人说 500 万行.那么,你觉得这个数值多少才合适呢? 曾经在中国互联网技术圈广为流传着这么一个 ...

  7. MySQL单表数据不要超过500万行:是经验数值,还是黄金铁律?

    本文阅读时间大约3分钟. 梁桂钊 | 作者 今天,探讨一个有趣的话题:MySQL 单表数据达到多少时才需要考虑分库分表?有人说 2000 万行,也有人说 500 万行.那么,你觉得这个数值多少才合适呢 ...

  8. mySQL单表限制大小

    MySQL单表大小的限制在目前的技术环境中,由所在主机的OS上面的文件系统来界定而不是由MySQL数据库本身来决定了. 在老版本的MySQL 3.22中,MySQL单表大小为4GB,当时的MySQL的 ...

  9. 一文了解MySQL性能测试及调优中的死锁处理方法,你还看不明白?

    一文了解MySQL性能测试及调优中的死锁处理方法,你还看不明白? 以下从死锁检测.死锁避免.死锁解决3个方面来探讨如何对MySQL死锁问题进行性能调优. 死锁检测 通过SQL语句查询锁表相关信息: ( ...

随机推荐

  1. 【Linux常见命令】cp命令

    cp - copy files and directories 拷贝文件或目标文件夹,默认不能直接拷贝目录,通过-r参数设置递归复制目录 copy 语法: cp [OPTION]... [-T] SO ...

  2. 15.Why lambda forms in python does not have statements?

    Why lambda forms in python does not have statements? A lambda form in python does not have statement ...

  3. 《例说51单片机(C语言版)(第3版)》——1-3 认识MCS-51的存储器结构

    本节书摘来异步社区<例说51单片机(C语言版)(第3版)>一书中的第1章,第1.3节,作者:张义和,王敏男,许宏昌,余春长,更多章节内容可以访问云栖社区"异步社区"公众 ...

  4. 使用mvp+rxjava+retrofit加载数据

    将mvp和rxjava和retrofit简单整合的列子,让activity的代码不再那么臃肿,只负责显示数据. 关于mvp的介绍可以看这里, 关于Rxjava的介绍可以看这里; 关于retrofit的 ...

  5. 数学--数论--HDU1825(积性函数性质+和函数公式+快速模幂+非互质求逆元)

    As we all know, the next Olympic Games will be held in Beijing in 2008. So the year 2008 seems a lit ...

  6. visibility: hidden 和 display: none的区别

    相同点: 两者都可以将dom元素隐藏 不同点: 1.display: none 隐藏之后不占用文档流,而visibility: hidden却会占用文档流,如果要在隐藏元素的同时获取其尺寸信息,那就可 ...

  7. 《Docker从入门到跑路》之网络模型介绍

    Bridge模式 当我们安装完docker后,启动Docker daemon,就会在主机上看到一个docker0的网桥,默认在此主机上启动的容器都会连接到这个网桥上.虚拟网桥的工作方式和物理交换机的工 ...

  8. B. Phoenix and Beauty(贪心构造)

    \(给定序列长n的数组和k.完美数组的定义是数组中每一个连续k项的子段和为定值\) \(现在要求插入一些数使得数组满足条件,输出你构造的新数列.\) \(\color{Red}{----------- ...

  9. 最小点覆盖(König定理)

    König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数.如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选了一个点就相当于覆盖了以它为端点的所有 ...

  10. Spring Cloud 学习 之 Spring Cloud Eureka(源码分析)

    Spring Cloud 学习 之 Spring Cloud Eureka(源码分析) Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 ...