MySQL 保存点在 Web 服务中的实际用途?

发布于 2024-07-13 20:22:19 字数 1114 浏览 8 评论 0原文

有谁有使用 MySQL savepoints (直接或通过 ORM),尤其是在重要的 Web 服务中? 你在哪里实际使用过它们? 它们是否足够可靠(假设您愿意运行 MySQL 的最新版本)或者太前沿或太昂贵?

最后,有人有类似以下用例的经验吗?您是否使用过保存点? 假设某些特定工作单元的要点是向 Orders 表添加一行(或者其他表,当然不一定与订单相关)并更新 OrdersAuditInfo 表,在同一事务中。 如果可能的话,更新Orders是很重要的,但是OrdersAuditInfo表并不是那么重要(例如,可以只将错误记录到文件中,但继续下去)与整体交易有关)。 在低层次上,它可能看起来像这样(警告,伪 SQL 如下):

BEGIN;

INSERT INTO Orders(...) VALUES (...);
/* Do stuff outside of SQL here; if there are problems, do a
 ROLLBACK and report an error (i.e., Order is invalid in this
 case anyway). */

SAVEPOINT InsertAudit;
INSERT INTO OrdersAudit(...) VALUES(...);
/* If the INSERT fails, log an error to a log file somewhere and do: */
ROLLBACK TO SAVEPOINT InsertAudit;

/* Always want to commit the INSERT INTO Orders: */
COMMIT;

但即使在这里,也许会有更好的(或至少更常见的)习惯用法? 人们可以将 OrdersAuditInfo 插入到完全不同的事务中,但最好能保证 OrdersAuditInfo不会被写入,除非最终的COMMIT确实有效。

Does anyone have experience they can share using MySQL savepoints (directly or via an ORM), especially in a non-trivial web service? Where have you actually used them? Are they reliable enough (assuming you're willing to run a fairly recent version of MySQL) or too bleeding-edge or expensive?

Lastly, does anyone have experience with something like the following use case and did you use savepoints for it? Say the main point of some specific unit of work is to add a row to an Orders table (or whatever, doesn't have to be order-related, of course) and update an OrdersAuditInfo table, in the same transaction. It is essential that Orders be updated if at all possible, but OrdersAuditInfo table is not as essential (e.g., it's ok to just log an error to a file, but keep going with the overall transaction). At a low level it might look like this (warning, pseudo-SQL follows):

BEGIN;

INSERT INTO Orders(...) VALUES (...);
/* Do stuff outside of SQL here; if there are problems, do a
 ROLLBACK and report an error (i.e., Order is invalid in this
 case anyway). */

SAVEPOINT InsertAudit;
INSERT INTO OrdersAudit(...) VALUES(...);
/* If the INSERT fails, log an error to a log file somewhere and do: */
ROLLBACK TO SAVEPOINT InsertAudit;

/* Always want to commit the INSERT INTO Orders: */
COMMIT;

But even here perhaps there'd be a better (or at least more common) idiom? One could do the OrdersAuditInfo insert in a completely different transaction but it would be nice to be guaranteed that the OrdersAuditInfo table were not written to unless the final COMMIT actually worked.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

哭泣的笑容 2024-07-20 20:22:19

我通常倾向于避免保存点,因为它会使代码很难理解和验证。

在您发布的情况下,包装在单个事务中将取决于 OrdersAudit 记录与 Orders 完全对应是否是您业务规则的一部分。

编辑:只需重新阅读您的问题,您不需要保证 OrdersAuditOrders 之间的对应关系。 因此,我不会使用任何事务来插入 OrdersAudit 记录。

I generally tend to avoid SAVEPOINTs, as it can make code quite hard to understand and verify.

In the case you posted, wrapping in a single transaction will depend on whether having OrdersAudit records exactly corresponding with Orders, is part of your business rules.

EDIT: Just re-read your question, and you do not have a requirement for guaranteed correspondence between OrdersAudit and Orders. So I wouldn't use any transaction for the insertion of the OrdersAudit records.

唔猫 2024-07-20 20:22:19

我相信您正在使用保存点来避免 INSERT 回滚整个事务失败。 但在这种情况下,最好的方法是使用 INSERT IGNORE。 如果失败,您将收到警告而不是错误,并且不会回滚任何内容。

由于您不需要回滚,因此我建议您不要使用事务。

如果您可能想要回滚一些成功的语句(但不是所有语句),SAVEPOINT 非常有用。 例如:

  1. 开始交易;
  2. 您不想经常运行的相对较慢的查询
  3. INSERT INTO a
  4. SAVEPOINT;
  5. SELECT id INTO @id FROM slot WHERE status = 'free' ORDER BY timestamp LIMIT 1;
  6. 插入 b (slot_id, ...) 值 (@id, ...)
  7. 插入 c (slot_id, ...) 值 (@id, ...)
  8. 插入 d (slot_id, ...) 值 ( @id,...)
  9. 提交;

如果SELECT没有返回任何内容,您可以运行全局ROLLBACK。 如果以下任何插入失败,您可以ROLLBACK TO SAVEPOINT one并选择另一个id。 显然,在这种情况下,您希望在代码中实现最大尝试次数。

I believe you are using a savepoint to avoid failed INSERTs to rollback the whole transaction. But in that case, the best way to do so is to use INSERT IGNORE. If it fails you will get a warning instead of an error, and nothing will rollback.

Since you don't need a rollback, I suggest you don't use a transaction.

SAVEPOINTs are great if you may want to rollback some successful statements (but not all statements). For example:

  1. START TRANSACTION;
  2. Relatively slow query that you don't want to run often
  3. INSERT INTO a
  4. SAVEPOINT one;
  5. SELECT id INTO @id FROM slot WHERE status = 'free' ORDER BY timestamp LIMIT 1;
  6. INSERT INTO b (slot_id, ...) VALUES (@id, ...)
  7. INSERT INTO c (slot_id, ...) VALUES (@id, ...)
  8. INSERT INTO d (slot_id, ...) VALUES (@id, ...)
  9. COMMIT;

If the SELECT returns nothing, you may run a global ROLLBACK. If any of the following INSERTs fails, you may ROLLBACK TO SAVEPOINT one and pick another id. Obviously, in a case like this, you want to implement a maximum number of attempts in your code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文