mysql在update,非主键索引更新引起死锁问题

 更新时间:2023年08月29日 10:08:23   作者:susu1083018911  
这篇文章主要介绍了mysql在update,非主键索引更新引起死锁问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

mysql在update,非主键索引更新引起死锁

1.mysql存储引擎

Innodb:支持事务,更新时采用行级锁,并发性高

MyISAM:不支持事务,更新时表锁,并发性差

因此使用Innodb才会发生死锁,从mysql5.6开始默认引擎Innodb

2.update更新过程

行级锁并不是直接锁记录,而是锁索引,如果一条SQL语句用到了主键索引,mysql会锁住主键索引;如果一条语句操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引。

反之:

  • 如果操作用到了主键索引会先在主键索引上加锁,然后在其他索引上加锁。
  • 如果没有用到索引,则进行全表扫描,锁表。

当where条件为非主键索引,执行update时,会经过一下步骤:

1)先获取非主键索引的行级锁;

2)由数据库基本原理可知,where条件为非主键索引时,会发生回表查询,进而再获得主键索引的行级锁;

3)更新完毕,进行事务提交。

根据上述步骤可知,对于非主键索引的update操作,其加锁过程并非原子操作,而且是分别需要获取不同索引的行级锁,可能会产生死锁:

假如:

一条update语句用到主键索引和非主键索引,则获取锁的顺序是先获取主键索引,再获取非主键索引;

而同时,另一条update语句只用到非主键索引,则获取锁的顺序是先获取非主键索引,再获取主键索引,二者正好发生在步骤 1)和 2)中间,则会造成锁。

3.解决方案

where条件加主键索引

先上锁查询查出来,在根据主键更新

逐条更新

行级锁是锁索引:

由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的

mysql批量update死锁

项目使用了多线程,同时调用service中的update方法更新数据,之前由于在update方法上加了synchronized做了线程同步,没有出现mysql update死锁的问题。

但是由于update更新耗时比较长,synchronized锁住对象,导致调用service中的其他方法阻塞,效率地下,于是优化synchronized,移到方法内部的同步代码段,然后虽然效率提高了,但是mysql总是出现死锁的bug:

Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found 
when trying to get lock; try restarting transaction; 

发生原因

T1:begin tran select * from table lock in share mode update table set column1='hello'

T2:begin tran select * from table lock in share mode update table set column1='world'

假设 T1 和 T2 同时达到 select,T1 对 table 加共享锁,T2 也对 table 加共享锁,当 T1 的 select 执行完,准备执行 update 时,根据锁机制,T1 的共享锁需要升级到排他锁才能执行接下来的 update.在升级排他锁前,必须等 table 上的其它共享锁(T2)释放,同理,T2 也在等 T1 的共享锁释放。于是死锁产生了。

因此,当sql发出一个update请求之后,数据库会对表中的每条记录加上共享锁。

然后数据库会根据where条件,将符合条件的记录转换为排他锁(mysql innodb默认对索引加锁),我们的多个线程update时,就出现了上面的情况,发生了死锁。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • MySql数据库基础之子查询详解

    MySql数据库基础之子查询详解

    所谓子查询是指在一个查询中嵌套了其他的若干查询,即在一个SELECT查询语句的WHERE或FROM子句中包含另一个SELECT查询语句,下面这篇文章主要给大家介绍了关于MySQL子查询的相关资料,需要的朋友可以参考下
    2022-09-09
  • MySQL5.7 windows二进制安装教程

    MySQL5.7 windows二进制安装教程

    这篇文章主要为大家详细介绍了MySQL5.7 windows二进制安装教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • MyBatis 如何写配置文件和简单使用

    MyBatis 如何写配置文件和简单使用

    这篇文章主要介绍了MyBatis 如何写配置文件和简单使用的相关资料,需要的朋友可以参考下
    2017-01-01
  • MySql如何获取相邻数据

    MySql如何获取相邻数据

    这篇文章主要介绍了MySql如何获取相邻数据,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • mysql中int(3)和int(10)的数值范围是否相同

    mysql中int(3)和int(10)的数值范围是否相同

    依稀还记得有次面试,有面试官问我int(10)与int(11)有什么区别,当时觉得就是长度的区别吧,后来发现事情不是这么简单,这篇文章主要给大家介绍了关于mysql中int(3)和int(10)的数值范围是否相同的相关资料
    2021-10-10
  • mysql中json_extract的具体使用

    mysql中json_extract的具体使用

    mysql5.7版本开始支持JSON类型字段,本文主要介绍了mysql中json_extract的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-05-05
  • MySQL 清除表空间碎片的实例详解

    MySQL 清除表空间碎片的实例详解

    这篇文章主要介绍了MySQL 清除表空间碎片的实例详解的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-10-10
  • Mysql索引类型与基本用法实例分析

    Mysql索引类型与基本用法实例分析

    这篇文章主要介绍了Mysql索引类型与基本用法,结合实例形式分析了Mysql索引类型中普通索引、唯一索引、主键索引、组合索引、全文索引基本概念、原理与使用方法,需要的朋友可以参考下
    2020-06-06
  • 如何快速使用mysqlreplicate搭建MySQL主从

    如何快速使用mysqlreplicate搭建MySQL主从

    mysql-utilities工具集是一个集中了多种工具的合集,可以理解为是DBA的工具箱,本文介绍利用其中的mysqlreplicate工具来快速搭建MySQL主从环境。下面和小编一起来看看
    2019-05-05
  • 最新Navicat 15 for MySQL破解+教程 正确破解步骤

    最新Navicat 15 for MySQL破解+教程 正确破解步骤

    Navicat for MySQL是一个针对MySQL数据库而开发的第三方mysql管理工具,该软件可以用于 MySQL 数据库服务器版本 3.21 或以上的和 MariaDB 5.1 或以上,这篇文章主要介绍了最新Navicat 15 for MySQL破解+教程 正确破解步骤,需要的朋友可以参考下
    2023-04-04

最新评论