【问题标题】:Avoid damaged data for SELECT and UPDATE query and long-running task in between避免 SELECT 和 UPDATE 查询的损坏数据以及两者之间的长时间运行的任务
【发布时间】:2019-09-23 16:54:57
【问题描述】:

我有两个应用程序exporterpayment_handler

  • exporter 执行 SELECT * FROM orders WHERE status="PAID",处理行(大约 5 分钟),最后执行 UPDATE orders SET status="EXPORTED" WHERE status="PAID"
  • payment_handler 执行 UPDATE orders SET status="PAID" WHERE status="UNPAID"

如果没有事务隔离,这将导致在payment_handler 运行而exporter 处理行时更新错误的数据:导出器的UPDATE 语句会将SELECT 语句没有的订单标记为导出之前选择。

如果我将导出器包装在事务中并使用FOR UPDATE 限定符执行SELECT,则payment handler 将被阻止直到exporter 完成,因为MySQL 不允许status="PAID" 的新插入。但是付款处理程序不能被阻塞这么长时间。

我当前的解决方法是避免事务并在数据中创建我自己的“快照”:exporter 创建一个临时表export_ids 并执行如下插入:INSERT INTO export_ids SELECT id FROM order WHERE status="PAID"exporterorder 表的所有后续 SELECT 和 UPDATE 操作将加入/子选择 export_id 表。这在性能和存储方面都很好,因为一次导出在export_ids 中只有大约 100k 个条目。

但我想知道我使用 MySQL 的事务级别是否错误,是否有更好的方法来实现该行为?

【问题讨论】:

  • 也许你应该分享一些代码,以便我们更好地理解/了解你在做什么,因为代码告诉了超过“1000”个单词..
  • 也许我遗漏了一些东西 - 但是您在哪里看到可能的“竞争条件”? exporter 只选择带有status="PAID" 的行。 payment_handler 不会触及任何这些行。或者你真的在没有 WHERE 条件的情况下运行UPDATE orders SET status="EXPORTED"
  • @PaulSpiegel 我已将问题更新为更准确。 payment_handler 将状态更新为 exporter 执行 SELECT 和 UPDATE 的确切值。
  • 在我看来,您这样做是正确的。我不知道另一种避免阻塞的方法。当然,我假设您已尽一切努力加快导出程序的进程,但速度仍然很慢。
  • 您可以在github.com/gbirke/transaction-test查看代码示例

标签: mysql transactions transaction-isolation


【解决方案1】:

只是不要这样做:

UPDATE orders SET status="EXPORTED" WHERE status="PAID"

您确切地知道您选择了哪些行,因此您应该能够使用它们的主键来更新相同的行。所以你的查询应该是

UPDATE orders SET status="EXPORTED" WHERE id IN (<list of previously selected ids>)

这实际上等同于您对临时表所做的操作。在这种特殊情况下,这就是您所需要的。因为它不是关于事务和锁定,而只是关于识别正确的行。

注意:我并不是说您不需要锁。你可能会。但不适用于这两个任务。

【讨论】:

  • 他说他处理了大约 100k 行,所以临时表实际上很可能是更好的选择。 100.000*4 字节(整数)约为 0.4MB。您可以轻松使用内存引擎表。
  • @fancyPants 无论哪种方式,ID 都在应用程序中 - 那么为什么不使用它们呢?不要忘记 - 我们正在谈论一个运行 5 分钟的脚本。所以0.1秒或多或少不会有太大的伤害。但是 - 我什至不在乎使用哪种方法。关键是通过主键识别行。顺便说一句:我不会在写查询中使用临时表。根据服务器设置(日志格式),在某些崩溃情况下可能会出现问题。
猜你喜欢
  • 1970-01-01
  • 2018-04-02
  • 1970-01-01
  • 2021-07-14
  • 1970-01-01
  • 1970-01-01
  • 2011-01-10
  • 2018-08-25
  • 1970-01-01
相关资源
最近更新 更多