最近在开发的时候,在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. Django中修改DATABASES后,执行python manage.py ****报错!UnicodeEncodeError

    Django中修改DATABASES后,执行python manage.py ****报错!UnicodeEncodeError: 'latin-1' codec can't encode chara ...

  2. 数学--组合数学--当C(n,m)中n固定m++的递推模板

    ll power(ll a, ll b, ll p) { ll ans = 1 % p; for (; b; b >>= 1) { if (b & 1) ans = ans * a ...

  3. P1516 青蛙的约会和P2421 [NOI2002]荒岛野人

    洛谷 P1516 青蛙的约会 . 算是手推了一次数论题,以前做的都是看题解,虽然这题很水而且还交了5次才过... 求解方程\(x+am\equiv y+an \pmod l\)中,\(a\)的最小整数 ...

  4. .net core 基于Dapper 的分库分表开源框架(core-data)

    一.前言 感觉很久没写文章了,最近也比较忙,写的相对比较少,抽空分享基于Dapper 的分库分表开源框架core-data的强大功能,更好的提高开发过程中的效率: 在数据库的数据日积月累的积累下,业务 ...

  5. spark系列-7、spark调优

    官网说明:http://spark.apache.org/docs/2.1.1/tuning.html#data-serialization 一.JVM调优 1.1.Java虚拟机垃圾回收调优的背景 ...

  6. andorid jar/库源码解析之Bolts

    目录:andorid jar/库源码解析 Bolts: 作用: 用于链式执行跨线程代码,且传递数据 栗子: Task.call(new Callable<Boolean>() { @Ove ...

  7. SpringBoot返回JSON日期格式问题

    SpringBoot中默认返回的日期格式类似于这样: "birth": 1537407384500 或者是这样: "createTime": "201 ...

  8. YOLACT : 首个实时one-stage实例分割模型,29.8mAP/33.5fps | ICCV 2019

    论文巧妙地基于one-stage目标检测算法提出实时实例分割算法YOLACT,整体的架构设计十分轻量,在速度和效果上面达到很好的trade-off.   来源:[晓飞的算法工程笔记] 公众号 论文: ...

  9. LeetCode--Array--Two sum (Easy)

    1.Two sum (Easy)# Given an array of integers, return indices of the two numbers such that they add u ...

  10. 用Visual Studio2019自定义项目模板

    项目模板简介 众所周知,在我们使用VS新建项目时,都需要选择一个项目模板,如下图: 我们选择完项目模板进行创建,创建完成之后,可以发现项目中已经包含了一些基础的文件.例如MVC: 可以看到,MVC项目 ...