MySQL 事务难题
我需要在单个原子事务中执行多次插入。例如:
开始交易;
插入...
插入...
提交;
然而,当 MySQL 遇到错误时,它只会中止导致错误的特定语句。例如,如果第二个插入语句中有错误,提交仍然会发生,并且第一个插入语句将被记录。因此,当发生错误时,MySQL 事务并不是真正的事务。为了解决这个问题,我使用了一个错误退出处理程序来回滚事务。现在交易已悄然中止,但我不知道问题出在哪里。
所以你面临的难题是:
如何让 MySQL 在遇到错误时中止事务,并将错误代码传递给调用者?
I need to perform several inserts in a single atomic transaction. For example:
start transaction;
insert ...
insert ...
commit;
However when MySQL encounters an error it aborts only the particular statement that caused the error. For example, if there is an error in the second insert statement the commit will still take place and the first insert statement will be recorded. Thus, when errors occur a MySQL transaction is not really a transaction. To overcome this problem I have used an error exit handler where I rollback the transaction. Now the transaction is silently aborted but I don't know what was the problem.
So here is the conundrum for you:
How can I both make MySQL abort a transaction when it encounters an error, and pass the error code on to the caller?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
MySQL 确实会将错误代码传递给调用者,并且根据此错误代码,调用者可以自由决定是否要提交目前完成的工作(忽略此特定 INSERT< 的错误) /code> 语句)或回滚事务。
这与
PostgreSQL
不同,后者总是在出错时中止事务,这种行为是许多问题的根源。更新:
在存储过程中使用无条件
ROLLBACK
是一种不好的做法。存储过程是可堆栈的,而事务则不然,因此嵌套存储过程中的
ROLLBACK
将回滚到事务的最开始位置,而不是回滚到存储过程执行的状态。如果要使用事务在错误时恢复数据库状态,请使用
SAVEPOINT
构造和DECLARE HANDLER
回滚到保存点:任一插入失败都将回滚所做的所有更改按该程序并退出。
MySQL
does pass error code to the caller and based on this error code the caller is free to decide whether it wants to commit work done up to the moment (ignoring the error with this particularINSERT
statement) or to rollback the transaction.This is unlike
PostgreSQL
which always aborts the transaction on error and this behavior is a source of many problems.Update:
It's a bad practice to use an unconditional
ROLLBACK
inside the stored procedures.Stored procedures are stackable and transactions are not, so a
ROLLBACK
within a nested stored procedure will roll back to the very beginning of the transaction, not to the state of the stored procedure execution.If you want to use transactions to restore the database state on errors, use
SAVEPOINT
constructs andDECLARE HANDLER
to rollback to the savepoints:Failure in either insert will roll back all changes made by the procedure and exit it.
使用Quassnoi先生的例子,这是我捕捉特定错误的最佳方法:
这个想法是使用tvariable来捕捉简单的错误消息,然后你可以捕捉你认为可能发生的sql状态,将自定义消息保存到你的变量中:
然后你只需进行通常的调用,并对变量执行 select 语句,例如:
如果没有错误,则返回 NULL;如果出现错误,则返回消息错误。如果您需要持久的错误消息,您可以选择创建一个表来存储它。
它很乏味而且不太灵活,因为需要为您想要捕获的每个状态代码提供一个 DECLARE EXIT HANDLER 段,它也不会显示详细的错误消息,但是嘿,它可以工作。
Using Mr. Quassnoi's example, here's my best approach to catching specific errors:
The idea is to use a tvariable to catch a simple error message, then you can catch sql states you think may happen to save custom messages to your variable:
Then you just do your usual call, and do a select statement for the variable like:
This will return either NULL if no error, or the message error in case of an error. If you need persistent error message you can optionally create a table to store it.
It's tedious and not very flexible because requires a DECLARE EXIT HANDLER segment for each status code you want to catch, it won't also show detailed error messages but hey, it works.