nodejs pg没有嵌套的事务

时间:2016-07-21 09:55:58

标签: node.js postgresql transactions

我想知道是否可以运行一系列SQL语句并将它们全部提交到单个事务中。

我正在看的场景是一个数组有一系列我希望插入表中的值,而不是单独但作为一个单元。

我正在查看以下项目,该项目使用pg为节点中的事务提供框架。单个事务看起来是彼此嵌套的,所以我不确定这对于包含可变数量元素的数组是如何工作的。

https://github.com/brianc/node-postgres/wiki/Transactions

var pg = require('pg');
var rollback = function(client, done) {
  client.query('ROLLBACK', function(err) {
    //if there was a problem rolling back the query
    //something is seriously messed up.  Return the error
    //to the done function to close & remove this client from
    //the pool.  If you leave a client in the pool with an unaborted
    //transaction weird, hard to diagnose problems might happen.
    return done(err);
  });
};
pg.connect(function(err, client, done) {
  if(err) throw err;
  client.query('BEGIN', function(err) {
    if(err) return rollback(client, done);
    //as long as we do not call the `done` callback we can do 
    //whatever we want...the client is ours until we call `done`
    //on the flip side, if you do call `done` before either COMMIT or ROLLBACK
    //what you are doing is returning a client back to the pool while it 
    //is in the middle of a transaction.  
    //Returning a client while its in the middle of a transaction
    //will lead to weird & hard to diagnose errors.
    process.nextTick(function() {
      var text = 'INSERT INTO account(money) VALUES($1) WHERE id = $2';
      client.query(text, [100, 1], function(err) {
        if(err) return rollback(client, done);
        client.query(text, [-100, 2], function(err) {
          if(err) return rollback(client, done);
          client.query('COMMIT', done);
        });
      });
    });
  });
});

我的数组逻辑是:

banking.forEach(function(batch){
  client.query(text, [batch.amount, batch.id], function(err, result);
} 

2 个答案:

答案 0 :(得分:1)

pg-promise为交易提供了非常灵活的支持。请参阅Transactions

它还支持部分嵌套事务,即保存点。

库会自动实现事务,这是当前应该使用的事务,因为如果您尝试手动组织事务,就会出现太多问题。

查看相关问题:Optional INSERT statement in a transaction

答案 1 :(得分:1)

这里有一个简单的 TypeScript 解决方案来避免 pg-promise

import { PoolClient } from "pg"
import { pool } from "../database"

const tx = async (callback: (client: PoolClient) => void) => {
  const client = await pool.connect();

  try {
    await client.query('BEGIN')
    try {
      await callback(client)
      await client.query('COMMIT')
    } catch (e) {
      await client.query('ROLLBACK')
    }
  } finally {
    client.release()
  }
}

export { tx }

用法:

...

let result;

await tx(async client => {
  const { rows } = await client.query<{ cnt: string }>('SELECT COUNT(*) AS cnt FROM users WHERE username = $1', [username]);
  result = parseInt(rows[0].cnt) > 0;
});

return result;