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

时间:2020-04-22 20:12:48

标签: javascript postgresql 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 = $1 and thing_id IN ($2: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 ($1:csv)`, [thingIDs])
}

我想一起运行它们,所以如果其中一个失败,则另一个回滚。实际上,我故意在第一个SQL查询中留下了错误。

这是我的发送功能:

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

第一个查询运行并运行。第二次失败。在这种情况下,我需要能够将它们回滚。谢谢!

2 个答案:

答案 0 :(得分:2)

来自pg-promise的作者。


它对您不起作用的原因是,这两个查询函数使用根数据库连接上下文,而不是事务上下文,即您正在事务连接外部执行查询。

您可以更改它们以支持可选的任务/事务上下文:

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 = $1 and thing_id IN ($2: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 ($1:csv)`, 
                          [thingIDs]);
}

使用batch(这是一种旧方法,仅在特殊情况下需要使用)没有意义。

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

答案 1 :(得分:1)

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