【问题标题】:Postgres promise multiple queries - nodejsPostgres 承诺多个查询 - nodejs
【发布时间】:2017-02-25 02:18:14
【问题描述】:

读完https://stackoverflow.com/a/14797359/4158593:关于nodejs单线程,它接受异步函数的第一个参数,处理它,然后在一切准备好时使用回调来响应。让我感到困惑的是,如果我有多个查询需要一次全部排除,并告诉 nodeJS 通过将它们添加到队列中来阻止其他请求。

为此,我意识到我需要将我的查询包装在另一个 callback 中。并且承诺做得很好。

    const psqlClient = psqlPool.connect(); 
    return psqlClient.query(`SELECT username FROM usernames WHERE username=$1`, ['me'])
    .then((data) => {
        if(!data.rows[0].username) {
           psqlClient.query(`INSERT INTO usernames (username) VALUES ('me')`);
        }
       else { ... } 
 });

此代码在注册期间使用,以检查在插入之前是否未使用用户名。所以nodejs将其他请求放入队列非常重要,并确保selectinsert同时进行。因为此代码可能允许同时发送的具有相同用户名的人选择已被使用的用户名,因此将插入两个用户名。

问题

  1. 上面的代码是否一次执行所有查询?

  2. 如果1 是正确的,如果我要像这样更改代码

    const psqlClient = psqlPool.connect(); 
    return psqlClient.query(`SELECT username FROM usernames WHERE username=$1`, ['me'], function(err, reply) { 
    if(!reply.rows[0].username) {
    psqlClient.query(`INSERT INTO usernames (username) VALUES ('me')`);
    }
    });
    

    这会影响行为吗?

  3. 如果1错了,该如何解决?我将需要这种模式(主要使用selectinsert/update 一个接一个),例如通过将每个文件的计数存储在我的数据库中来确保我的XML站点地图不包含超过50000个网址动态的。

【问题讨论】:

    标签: node.js postgresql promise es6-promise


    【解决方案1】:

    在您的情况下,唯一可以保证数据完整性的是单个 SELECT->INSERT 查询,此处已多次讨论。

    一些例子:

    您应该可以在这里找到更多内容;)


    我还在pg-promise 中的SELECT ⇒ INSERT 示例中谈到了这个主题。


    但是,还有一种替代方法,可以使任何重复的插入产生冲突,在这种情况下,您可以重新运行您的选择以获取新记录。但这并不总是一个合适的解决方案。

    【讨论】:

    • 谢谢,所以回调和承诺对我来说没有帮助,可能还有一些冲突?
    • @aloha_mate 是的,只能服务端解决。无论你在 Node.js 中使用什么技巧,它都无法保证数据的完整性。
    • @aloha_mate 除了我刚刚添加的额外解决方案,依赖于插入冲突。
    • 很酷,谢谢,是的,我考虑过了。使用UNIQUE 键和ON CONFLICT 也是一种解决方案,但需要重新运行查询:(所以我认为在一个查询中选择+插入是野兽!谢谢:D
    • @aloha_mate 解决什么问题?当然不是您发布的问题。
    【解决方案2】:

    这是来自 node-postgres 创建者的参考:https://github.com/brianc/node-postgres/issues/83#issuecomment-212657287。基本上查询是排队的,但不要在你有很多请求的生产环境中依赖它们......

    但是你可以使用BEGINCOMIT

    var Client = require('pg').Client;
    
    var client = new Client(/*your connection info goes here*/);
    client.connect();
    
    var rollback = function(client) {
      //terminating a client connection will
      //automatically rollback any uncommitted transactions
      //so while it's not technically mandatory to call
      //ROLLBACK it is cleaner and more correct
      client.query('ROLLBACK', function() {
        client.end();
      });
    };
    
    client.query('BEGIN', function(err, result) {
      if(err) return rollback(client);
      client.query('INSERT INTO account(money) VALUES(100) WHERE id = $1', [1], function(err, result) {
        if(err) return rollback(client);
        client.query('INSERT INTO account(money) VALUES(-100) WHERE id = $1', [2], function(err, result) {
          if(err) return rollback(client);
          //disconnect after successful commit
          client.query('COMMIT', client.end.bind(client));
        });
      });
    });
    

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

    但是,这不会阻塞表。以下是解决方案列表:Update where race conditions Postgres (read committed)

    【讨论】:

    • 事务和重复插入与SELECT->INSERT 逻辑的完整性无关,这是您的问题。
    • @vitaly-t 是的,但是 begincommit 之间的查询可以使用承诺多次执行(选择 -> 插入),据我所知,它会将其他传入查询排队。如果我错了,请纠正我
    • 它将在单个 begin/commit 块中排队查询,而不是跨越它们,这正是最初的问题 - 竞争条件。这无法解决任何问题。
    猜你喜欢
    • 1970-01-01
    • 2019-10-21
    • 1970-01-01
    • 2018-01-31
    • 1970-01-01
    • 2018-05-27
    • 2023-01-21
    • 2019-09-29
    • 2019-03-19
    相关资源
    最近更新 更多