当事务中的任务使用 pg-promise 失败时如何回滚事务

How to rollback a transaction when a task in transaction fails with pg-promise

假设我有两个函数:

export const setThingAlertsInactive = (userID, thingIDs) => {
    return db.any(' UPDATE thing_alerts SET is_active = false WHERE IN (Select * from thing_alerts where user_id =  and thing_id IN (:csv))', [userID.toString(), thingIDs])
}

export const archiveOrRestoreThings = (thingIDs, archive) => {
    let archivedStatement =''
    if(archive === true){
        archivedStatement = 'archived = current_timestamp'
    } else if(archive === false){
        archivedStatement = 'archived = NULL'
    }
    return db.none(`UPDATE things SET ${archivedStatement} WHERE id IN (:csv)`, [thingIDs])
}

我想 运行 将它们放在一起,这样如果一个失败,另一个就会回滚。事实上,我故意在第一个 SQL 查询中留下错误。

这是我的 tx 函数:

export const archiveOrRestoreThingsAndSetAlert = (userID, thingsIDs, archive) => {
    return db.tx((transaction) => {
        const queries = [archiveOrRestoreThings(thingIDs, archive), setThingAlertsInactive(userID, projectIDs)]
        return transaction.batch(queries)
    })
}

第一个查询 运行s 并且有效。第二个失败了。在那种情况下,我需要能够将它们回滚。谢谢!

您需要将事务传递给 archiveOrRestoreThings 和 setThingAlertsInactive 并在事务上调用 .none 和 .any 而不是数据库。请参阅 example code 以供参考。

来自 pg-promise 的作者。


它对你不起作用的原因是因为这两个查询函数使用根数据库连接上下文,而不是事务context/scope,即你在事务之外执行查询connection/scope.

您可以更改它们以支持可选的 task/transaction 上下文:

export const setThingAlertsInactive = (userID, thingIDs, t) => {
    return (t || db).none(`UPDATE thing_alerts SET is_active = false WHERE
           IN (Select * from thing_alerts where user_id =  and thing_id IN (:csv))`,
           [userID.toString(), thingIDs]);
}

export const archiveOrRestoreThings = (thingIDs, archive, t) => {
    let archivedStatement = '';
    if(archive === true) {
        archivedStatement = 'archived = current_timestamp'
    } else if(archive === false) {
        archivedStatement = 'archived = NULL'
    }
    return (t || db).none(`UPDATE things SET ${archivedStatement} WHERE id IN (:csv)`, 
                          [thingIDs]);
}

并且没有必要使用 batch,这是一种遗留方法,仅在特殊情况下才需要:

export const archiveOrRestoreThingsAndSetAlert = (userID, thingsIDs, archive) => {
    return db.tx(async t => {
        await archiveOrRestoreThings(thingIDs, archive, t);
        await setThingAlertsInactive(userID, projectIDs, t);
    })
}