6

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.

4

2 回答 2

1

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

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

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

于 2009-03-03T06:34:00.673 回答
0

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

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

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

  1. 开始交易;
  2. 您不想经常运行的相对较慢的查询
  3. 插入一个
  4. 保存点一;
  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. INSERT INTO d (slot_id, ...) 值 (@id, ...)
  9. 犯罪;

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

于 2021-10-12T12:33:43.083 回答