Postgresql 捕获事务错误并回滚
Postgresql Catching Transaction Error and Rollback
我正在使用 pg-promise 来 运行 我的 SQL 查询。查询本身存储在外部 .sql 文件中。
当我执行事务时,如果发生错误(如预期),Postgres 将中止事务。我 运行 遇到的问题是在事务中止后我尝试 运行 的任何单独查询都不是 运行 而是我收到此消息:
"current transaction is aborted, commands ignored until end of transaction block"。如果查询在 psql 控制台中被 运行,我可以通过在查询失败后发出 ROLLBACK 来解决这个问题。我不认为这是一个选项,因为我的应用程序使用的 SQL 位于外部文件中。我也不认为 Savepoints 是一个选项,因为如果出现故障,整个事务都应该被丢弃。
如果发生此错误,我如何在 SQL 文件中回滚?
这里是SQL供参考:
BEGIN;
DELETE
FROM tournament_tossup_values
WHERE tournament_id = AND
NOT EXISTS
(
SELECT id
FROM tournament_match
WHERE tournament_id =
);
UPDATE tournament
SET bonus_point_value = , parts_per_bonus =
WHERE id = AND NOT EXISTS (
SELECT id
FROM tournament_match
WHERE tournament_id =
)
RETURNING bonus_point_value, parts_per_bonus; <-- Any subsequent accesses to the database by the application fail if this transaction fails
COMMIT; <-- I want to rollback everything if this fails
提前致谢!
在外部 SQL 文件中实现事务时,您需要为 COMMIT
和 ROLLBACK
提供所有正确的处理。如果您不这样做,事务状态可能会在您的服务器端代码中变得不可预测,并导致您遇到的错误类型。
这可能有点棘手,说起来容易做起来难。这就是为什么最好的解决方案是根本不这样做。
模块 pg-promise that you are already using provides reliable handling for transactions, via method tx,这是您应该使用的。
来自 tx
方法文档:
Executes a callback function as a transaction (...)
A transaction wraps a regular task into additional queries:
it executes BEGIN
just before invoking the callback function
it executes COMMIT
, if the callback didn't throw any error or return a
rejected promise, it executes ROLLBACK
, if the callback did throw an
error or return a rejected promise
it executes corresponding
SAVEPOINT
commands when the method is called recursively.
为此,将您的 SQL 文件分成两个文件 - 一个包含您的 DELETE
操作,一个包含您的 UPDATE
操作,然后将它们作为两个查询在一个交易:
await db.tx(async t => {
await t.none('DELETE...');
await t.any('UPDATE...');
});
我正在使用 pg-promise 来 运行 我的 SQL 查询。查询本身存储在外部 .sql 文件中。
当我执行事务时,如果发生错误(如预期),Postgres 将中止事务。我 运行 遇到的问题是在事务中止后我尝试 运行 的任何单独查询都不是 运行 而是我收到此消息: "current transaction is aborted, commands ignored until end of transaction block"。如果查询在 psql 控制台中被 运行,我可以通过在查询失败后发出 ROLLBACK 来解决这个问题。我不认为这是一个选项,因为我的应用程序使用的 SQL 位于外部文件中。我也不认为 Savepoints 是一个选项,因为如果出现故障,整个事务都应该被丢弃。
如果发生此错误,我如何在 SQL 文件中回滚?
这里是SQL供参考:
BEGIN;
DELETE
FROM tournament_tossup_values
WHERE tournament_id = AND
NOT EXISTS
(
SELECT id
FROM tournament_match
WHERE tournament_id =
);
UPDATE tournament
SET bonus_point_value = , parts_per_bonus =
WHERE id = AND NOT EXISTS (
SELECT id
FROM tournament_match
WHERE tournament_id =
)
RETURNING bonus_point_value, parts_per_bonus; <-- Any subsequent accesses to the database by the application fail if this transaction fails
COMMIT; <-- I want to rollback everything if this fails
提前致谢!
在外部 SQL 文件中实现事务时,您需要为 COMMIT
和 ROLLBACK
提供所有正确的处理。如果您不这样做,事务状态可能会在您的服务器端代码中变得不可预测,并导致您遇到的错误类型。
这可能有点棘手,说起来容易做起来难。这就是为什么最好的解决方案是根本不这样做。
模块 pg-promise that you are already using provides reliable handling for transactions, via method tx,这是您应该使用的。
来自 tx
方法文档:
Executes a callback function as a transaction (...)
A transaction wraps a regular task into additional queries:
it executes
BEGIN
just before invoking the callback functionit executes
COMMIT
, if the callback didn't throw any error or return a rejected promise, it executesROLLBACK
, if the callback did throw an error or return a rejected promiseit executes corresponding
SAVEPOINT
commands when the method is called recursively.
为此,将您的 SQL 文件分成两个文件 - 一个包含您的 DELETE
操作,一个包含您的 UPDATE
操作,然后将它们作为两个查询在一个交易:
await db.tx(async t => {
await t.none('DELETE...');
await t.any('UPDATE...');
});