6

我有menus,categoriesproducts表。我正在使用 mysql 5.5,所有表都是 innoDB,并且在所有情况下 id 都是具有自动增量的主键(int)。

menus table
id, name, status

categories table
id, menu_id, name

products table
id, menu_id, category_id, status, name, url, content

多个脚本可以并行运行,执行包含以下逻辑的同一个 php 文件。

START TRANSACTION;
SET autocommit = 0;

LOCK TABLES products WRITE, categories WRITE, menus WRITE;

SELECT 
  p.`id`,
  p.`name`,
  p.`url`,
  p.`status`,
  c.`id` cat_id,
  c.`name` cat_name,
  m.`id` `menu_id`,
  m.`name` menu_name
FROM
  products p 
  LEFT JOIN categories c 
    ON p.`subcategory_id` = c.`id` 
  LEFT JOIN menus m 
    ON p.`menu_id` = m.`id` 
   WHERE p.`status` = 0 LIMIT 1

如果找到选择结果后,它的状态更新为1(否则我回滚并释放锁)

UPDATE products SET status = 1 WHERE id = [product_id];

如果最后一个查询成功,我运行

COMMIT();
UNLOCK TABLES;

否则

ROLLBACK();
UNLOCK TABLES;

在此之后,脚本向该产品的 url 发出 curl 请求,以从中获取一些内容并相应地更新产品的行

// making curl request (might take a few dozen seconds, because proxy is being used and sometimes because of proxy failure the request is attempted again)

trying to update the products table 

    UPDATE products SET content = [received content], status = 2 WHERE id = [product_id]

因此,脚本在上述表上获取 X 锁,从 products 表中获取状态为 0(表示 - TODO)的一行,尝试将其状态设置为 1(表示 PENDING),然后解锁表。之后尝试在 php 中执行一些逻辑,最后尝试更新产品表 - 将内容列和状态更新为 2(表示完成)。

如果我并行运行 5 个脚本,在最后一步运行几分钟后(将产品更新为 DONE),我会收到此错误

Error: SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when try to get lock; try restarting transaction

当 2 个事务相互等待以相反的顺序更新相同的行时,我理解死锁的一般概念,但是在这种情况下我无法弄清楚死锁的原因。我的意思是脚本正在工作并以相同的顺序锁定表,因此如果一个脚本已锁定products(和其他)表,获取排他锁,另一个脚本应该在队列中等待这些锁被释放,所以它不应该导致死锁.
另一方面,每个脚本都在选择状态为 -> 0 的产品并尝试更新为 1,并且在从 1 到 2 的同一“会话”期间,所以我看不出这如何成为死锁的原因。我在这里想念什么?

编辑:

虽然我没有提到我如何使用类别和菜单表的信息,但我确实需要获取它们,它们的使用并不重要,因为我没有对它们进行任何数据库处理。

我曾经使用行级锁定SELECT FOR UPDATE,但是我遇到了像这个问题MySQL InnoDB dead lock on SELECT with exclusive lock (FOR UPDATE)这样的死锁,所以,我不得不将代码更改为表级锁定

谢谢

4

1 回答 1

1

您在这里做错了几件事。首先,您没有理由对表进行锁定。InnoDB 的设计目标之一是它具有行级锁定。

其次,您应该使用 SELECT FOR UPDATE 语句来锁定您正在使用的行,然后执行您的 UPDATE 和 COMMIT。

当这些表只是关于此更新的信息时,我也不明白为什么要将产品加入类别和菜单。这似乎是一个“数据处理”功能。

于 2016-02-03T17:02:31.077 回答