【问题标题】:Preventing and delaying concurent mysql insert防止和延迟并发mysql插入
【发布时间】:2014-04-17 09:57:27
【问题描述】:

我正在尝试创建一个订购系统并创建一个唯一的序列号来区分订单,它运行良好,直到有一次同时有订单(差异仅以秒为单位,大约 10 秒)和然后唯一的序列号变得相同(序列号从db中的最后一个序列号递增)。
我正在根据某种格式创建 id,它必须每月重置,所以我不能使用 uniqid()。

你们对此有什么想法吗?我读到了一些数据库锁定,但是当我尝试这个解决方案 "Can we lock tables while executing a query in Zend-Db" 时它也没有用。

---编辑---

格式是

projectnumber-year-本月订单数

本月订单数为 4 位数字,从 0001 开始到 9999 9999 之后会从 A001 ... A999 B001 ... ZZZZ 重新开始

这是专栏
| order_id | varchar(17) | utf8_general_ci |否 |优先级 |

我希望这让现在更清楚:)

谢谢!

【问题讨论】:

  • 你能展示你用来创建唯一 id 的语句以及你的表结构吗?
  • @DanFromGermany 我已经添加了更多细节,请参阅编辑后的问题。谢谢!

标签: php mysql unique


【解决方案1】:

我主要考虑使用 AUTO_INCREMENT 主键 - 有关详细信息,请参阅 manual

如果这是不可能的,并且您正在使用 InnoDB,您应该能够在 Transaction 中创建订单。然后,您可以在您的应用程序中检测是否存在重复并根据需要重新颁发新 ID。如果您的订单创建失败,使用事务将确保数据库中没有残留数据。

根据附加信息进行编辑

我会添加一个AUTO_INCREMENT 主键,并为所需格式使用单独的“OrderName”列。这应该允许您执行以下操作,例如:

UPDATE orders o 
 JOIN (
  SELECT 
   year(o2.dte) y,
   month(o2.dte) m,
   min(o2.Order_ID) minid 
  FROM orders o2 GROUP BY y,m) AS t ON (t.m=month(dte) AND t.y=year(dte)) 
SET o.OrderName=CONCAT('p-n-',year(o.dte),"-",o.Order_ID-t.minid);

id 列是int PRIMARY KEY AUTO_INCREMENT 并且将确保订单始终处于正确的顺序并且不需要锁定。在此示例中,CONCAT 将规定您的订单号格式。如果您愿意,可以在触发器中运行此UPDATE,以确保立即填充 OrderName。当然,如果您在触发器中运行它,则无需重新填充整个表。

【讨论】:

  • 是的,我已经尝试检测是否有任何重复,但它没有帮助,我猜是因为时差太小了?谢谢!
  • 您可以在 1 秒内插入 1000 行而不会重复...使用 mysql 提供的机制来建立这一点:主键 + 自动增量。你甚至不需要锁定。锁定使用错误的方式会毁了你的生意^^
  • @DanFromGermany 是的,通常我将其用作唯一标识符,但这次是来自客户端的请求。不过感谢您的建议!
  • @nayoso 你必须确保数据一致性尤其是涉及到[buying|money|customers]的主题 i>,您必须使用,不仅是为了一致性,而且是为了外键支持。因此,您将实现 internal order_id - integer + primary key + auto increment,并且为了满足您的客户,您还将 实现第二列 调用 order_external_id varchar + unique index 并将您的自定义值放入此列。
  • @DanFromGermany 是的,但他们希望它每月重置一次。我想我必须再次和我的客户谈谈这个问题。以及如何防止 order_external_id 是唯一的?如果我根据主键进行检查?谢谢:)
【解决方案2】:

看来我们必须使用带有可序列化锁定的事务。它将阻止其他会话的读写,直到事务完成。

请看这里

http://en.wikipedia.org/wiki/Isolation_%28database_systems%29

http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html

【讨论】:

  • 我明白了,所以我只是在查询末尾添加 LOCK TABLE 表名 READ ?然后如果另一个用户试图读取处于锁定状态的数据库会发生什么?它会返回异常吗?谢谢!
  • 感谢 hoangvu!我会尝试检查文章!
猜你喜欢
  • 2011-09-27
  • 1970-01-01
  • 1970-01-01
  • 2011-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-15
  • 1970-01-01
相关资源
最近更新 更多