MySQL 保存点在 Web 服务中的实际用途?
有谁有使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我通常倾向于避免保存点,因为它会使代码很难理解和验证。
在您发布的情况下,包装在单个事务中将取决于
OrdersAudit
记录与Orders
完全对应是否是您业务规则的一部分。编辑:只需重新阅读您的问题,您不需要保证
OrdersAudit
和Orders
之间的对应关系。 因此,我不会使用任何事务来插入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 withOrders
, is part of your business rules.EDIT: Just re-read your question, and you do not have a requirement for guaranteed correspondence between
OrdersAudit
andOrders
. So I wouldn't use any transaction for the insertion of theOrdersAudit
records.我相信您正在使用保存点来避免
INSERT
回滚整个事务失败。 但在这种情况下,最好的方法是使用 INSERT IGNORE。 如果失败,您将收到警告而不是错误,并且不会回滚任何内容。由于您不需要回滚,因此我建议您不要使用事务。
如果您可能想要回滚一些成功的语句(但不是所有语句),
SAVEPOINT
非常有用。 例如:如果
SELECT
没有返回任何内容,您可以运行全局ROLLBACK
。 如果以下任何插入失败,您可以ROLLBACK TO SAVEPOINT one
并选择另一个id
。 显然,在这种情况下,您希望在代码中实现最大尝试次数。I believe you are using a savepoint to avoid failed
INSERT
s to rollback the whole transaction. But in that case, the best way to do so is to useINSERT 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.
SAVEPOINT
s are great if you may want to rollback some successful statements (but not all statements). For example:If the
SELECT
returns nothing, you may run a globalROLLBACK
. If any of the following INSERTs fails, you mayROLLBACK TO SAVEPOINT one
and pick anotherid
. Obviously, in a case like this, you want to implement a maximum number of attempts in your code.