关于插入和更新的Mysql死锁

时间:2014-07-18 07:51:36

标签: mysql

我在中高负荷情况下遇到死锁。以下是详细信息。

的MySQL-5.5.21-55

引擎:InnoDB

表:订单

# Field, Type, Null, Key, Default, Extra
id, bigint(20) unsigned, NO, PRI, , auto_increment
sno, varchar(32), NO, MUL, ,
misc1, int, NO, , 0,

表:OrderItem

# Field, Type, Null, Key, Default, Extra
id, bigint(20) unsigned, NO, PRI, , auto_increment
order_id, bigint(20), YES, MUL, , 
f1, varchar(50), YES, , , 
f2, varchar(100), YES, , , 
misc2, int, NO, , 0,
  • 订单 .sno是唯一的
  • OrderItem .order_id未定义为外键但在应用程序中用作外键
  • 订单 OrderItem
  • 一对多关系
  • OrderItem .order_id + OrderItem .f1 + OrderItem .f2是唯一的

USECASE:

  • 每当需要更新订单 OrderItem 中的任何记录时,我都希望使旧记录无效(或删除)并插入新记录。
  • 可能会发生这种情况,早些时候,订单中的一条记录(例如order1)在 OrderItem 中有3条记录(例如orderItem1,orderItem2,orderItem3)。但现在我希望将它作为order1-> orderItem1,orderItem4,orderItem5或全​​新的集合。这就是为什么我想要将旧记录无效并插入新记录的原因,因为找出 OrderItem 中的更改很复杂。

多个线程将执行此操作;但他们会在不同的记录集上工作。我一次在25个订单上运行

我尝试了什么:

  • 插入订单;重复密钥更新订单并从 OrderItem 中删除所有子项并插入 OrderItem
  • 订单中添加另一列名为 is_active 的列,并将同一 sno 的所有记录标记为0,并在顺序;将新子项插入 OrderItem
  • 从给定sno的订单中删除;从 OrderItem 中删除相同的sno.Insert到两个表中。

上述所有方法都导致了一些或其他时间的deat锁定。 没有其他线程或进程在这些表上工作。

观察:

通过以下链接

发现更新/删除多条记录会导致MySQL在REPEATABLE_READ隔离级别(这是默认值)获取 Next Key 锁定。在我看来,这会导致问题。

感谢你能否就解决这个问题提供一些指导。

2 个答案:

答案 0 :(得分:1)

既然你没有提到它,我会试一试,你试过“FOR UPDATE”吗?

将连接自动提交设置为false。

在程序开头,使用它来锁定所有相关数据。

SELECT o.* , oi.* 
FROM order o 
INNER JOIN orderitem oi ON (o.id=oi.order_id) 
WHERE o.id = <order id to update> 
FOR UPDATE;

然后你可以对这些条目做任何你想做的事情。 然后提交。

编辑:我认为问题的根本原因是多线程(显然),我在想如果从等式中删除该元素会更好。

想象一下你有多个接收器接收请求的系统。那些接收器只会做类似的事情:

//select to check if there is a existing record(no need to lock), if no, return fail as response
SELECT o.* , oi.* 
FROM order o 
INNER JOIN orderitem oi ON (o.id=oi.order_id) 
WHERE o.sno = <sno to update>;

insert into request_buffer (request_id, sno, new_order_item,create_date .......) 
values
(1, abc , orderitem1......);
//return success after inserting buffer.

你有一个单独的单线程程序,它汇集了这个表并处理那些缓冲区条目。

在这种情况下,它将从DB更新过程中分离多线程元素。我不确定传入请求的数量,但我认为如果您在每个周期/查询中处理更多请求,那么性能不会有太大差异吗?

答案 1 :(得分:0)

最后,(也许是一种解决方法,与@ JackyCheng的建议一致),Im,

  • 插入订单表(一次多条记录); 重复密钥没有更新
  • 插入 OrderItem 表(一次多条记录);
  • 选择所有要更新的订单 .ids
  • 将已识别的订单(ids)标记为非活动 (这是关键部分,因为它使用索引键锁而不是下一个键锁)< / EM>

总体而言,25个订单的交易执行时间仍然低于30毫秒。