MySQL replace into 造成死锁

发布时间 2023-04-06 15:13:49作者: __Yoon

错误日志如下:

 

1.replace into 的作用是,当存在冲突时,会把旧的记录替换成新的记录,也就是说replace into 分了两个步骤:A.判断 和 B. 执行

A.  首先判断我们执行的记录是否存在(根据主键或者唯一索引)

B.  针对不存在的记录,直接执行insert语句

     针对已经存在的记录,语句拆分为:delete + insert 执行

2.测试如下:

mysql> show tables;
+----------------+
| Tables_in_yoon |
+----------------+
| hank           |
+----------------+
1 row in set (0.00 sec)

mysql> select * from hank;
+----+------+
| id | name |
+----+------+
|  1 | yoon |
|  2 | hank |
|  3 | yoon |
|  4 | aaa  |
+----+------+
4 rows in set (0.00 sec)

mysql> replace into hank (id,name) values (5,'CCC');
Query OK, 1 row affected (0.00 sec)

mysql> replace into hank (id,name) values (4,'KKK');
Query OK, 2 rows affected (0.00 sec)

3.死锁分析:

在多线程高并发的情况下,存在两个事务同时去获取一个记录的修改的情况:
A. 事务1拿到X记录锁
B. 事务2检测到冲突,获取X|NK锁,被事务1阻塞
C. 事务1检测到冲突,申请获取S|NK,被事务2阻塞

4.解决方法:(最好还是通过业务逻辑去优化)

使用 INSERT + ON DUPLICATE KEY UPDATE语句替换高并发环境下的Replace Into语句解决死锁问题
ON DUPLICATE KEY UPDATE语句的作用是:
A. 若该数据的主键值/ UNIQUE KEY 已经在表中存在,则执行更新操作, 即UPDATE 后面的操作
B. 否则插入一条新的记录