首页 技术 正文
技术 2022年11月15日
0 收藏 937 点赞 4,740 浏览 3045 个字

update的where条件要把索引的字段带上,要不然就全表锁

文章目录

update的where条件要把索引的字段带上,要不然就全表锁
        本文主要内容
        背景
        在学习中总结一下内容
        关于锁的表
        sql加锁思考点
        InnoDB行锁实现方式

本文主要内容

报错了: java.sql.BatchUpdateException: Lock wait timeout exceeded; try restarting transaction
对表进行更新和插入操作,在update的时候出现上述异常,经过排查发现是锁表的原因。
背景

建表语句如下:
    表名为: app_pay_log_test
    索引为:UNIQUE KEY rso_orderid_idx (rso,order_id)

CREATE TABLE `app_pay_log_test` (
      `rso` varchar(50) NOT NULL DEFAULT ‘-1’ COMMENT ‘充值渠道’,
      `order_id` varchar(100) NOT NULL COMMENT ‘订单id’,
      `amount` decimal(20,2) NOT NULL COMMENT ‘充值金额’,
      `product` varchar(50) DEFAULT NULL,
      UNIQUE KEY `rso_orderid_idx` (`rso`,`order_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=’手游充值订单’;

1
    2
    3
    4
    5
    6
    7

出现异常的执行操作为:

UPDATE `app_pay_log_test` SET `product`=$2 WHERE `order_id`=$1 AND `product` is NULL

1

这里全表扫描锁表了,update的where条件把索引的字段要带上,要不然就全表锁。
也就是说要把检索条件上加上索引。而本表的索引是联合索引,上面的sql没有走索引,导致去全表扫描,出现表锁。

解决办法:

UPDATE `app_pay_log_test` SET `product`=$2 WHERE `rso`=$0 AND `order_id`=$1 AND `product` is NULL

1

实际上,不管是插入更新查询都需要走索引才不会那么容易出现全表扫描。
在学习中总结一下内容

InnoDB行锁是通过给索引上的索引项加锁来实现的。
InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!
在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。
关于锁的表

由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。
MySQL 5.5 中,information_schema库中新增了三个关于锁的表,即 innodb_trx、innodb_locks 和 innodb_lock_waits.
其中 innodb_trx 表记录当前运行的所有事务,innodb_locks 表记录当前出现的锁,innodb_lock_waits 表记录锁等待的对应关系。
具体用法可以参考:表结构说明

SELECT * FROM information_schema.INNODB_TRX\G;
SELECT * FROM information_schema.innodb_locks \G
SELECT * FROM information_schema.innodb_lock_waits \G

1
    2
    3

在 innodb_trx 表的第一行,trx_id为360F表示事务id,状态(trx_state)为等待状态,线程ID为2,事务用到的表为1(trx_tables_in_use),有1(trx_tables_locked)个表被锁。可以使用 kill trx_mysql_thread_id 杀死这个sql线程。

mysql> SELECT * FROM information_schema.innodb_trx \G
    *************************** 1. row ***************************
                        trx_id: 360F
                     trx_state: LOCK WAIT
           trx_mysql_thread_id: 2
                     trx_query: UPDATE user SET name=”lock_waits” WHERE ID = 2
             trx_tables_in_use: 1
             trx_tables_locked: 1

1
    2
    3
    4
    5
    6
    7
    8

sql加锁思考点

前提一:筛选列是不是主键?
    前提二:当前系统的隔离级别是什么?(不同隔离级别 锁类型不同)
    前提三:筛选列如果不是主键,那么筛选列上有索引吗?
    前提四:筛选列上如果有二级索引,那么这个索引是唯一索引吗?(唯一索引只锁一行)
    前提五:两个SQL的执行计划是什么?索引扫描?全表扫描?(走行锁还是表锁或者间隙锁)

InnoDB行锁实现方式

InnoDB行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁
    在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。下面通过一些实际例子来加以说明。
    (1)在不通过索引条件查询的时候,InnoDB确实使用的是表锁,而不是行锁。
    (2)由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。
    (3)当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。
    (4)即便在条件中使用了索引字段,但是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的,如果MySQL认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。

参考:
MySQL SHOW PROCESSLIST协助故障诊断 http://www.ywnds.com/?p=9337
记一次数据库死锁Deadlock https://www.jianshu.com/p/1c8fecb00563
MySQL 5.5 InnoDB 锁等待 https://dbarobin.com/2015/01/27/innodb-lock-wait-under-mysql-5.5/
————————————————
版权声明:本文为CSDN博主「Agly_Charlie」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Agly_Clarlie/article/details/83032289

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,491
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,907
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,740
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,492
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,132
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,293