【问题标题】:How to rollback a transaction when a task in transaction fails with pg-promise当事务中的任务因 pg-promise 失败时如何回滚事务
【发布时间】:2020-08-06 00:22:28
【问题描述】:

假设我有两个功能:

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 Query 中留下错误的。

这是我的 tx 函数:

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

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

【问题讨论】:

    标签: javascript postgresql pg-promise


    【解决方案1】:

    来自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);
        })
    }
    

    【讨论】:

    • 已被大师解答。谢谢!我就是这样做的。
    【解决方案2】:

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

    【讨论】:

    • 完全错过了。谢谢前辈。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多