【问题标题】:JS - how to end a db connection with chained promiseJS - 如何用链式承诺结束数据库连接
【发布时间】:2020-05-10 16:29:08
【问题描述】:

我在一个文件中声明了我的数据库函数,并希望它们返回一个承诺,以便我可以在其他地方重新使用它们。问题是如何结束连接?我知道我可以在我调用数据库函数的每个地方调用conn.end(),但我不能在数据库函数本身中这样做吗?

来电者...

function scanBoard(qrCode) {
    getBoard(qrCode)
    .then(b => {
        board = b;
    });
}

DB 函数(注意,代码不会运行,因为它包含我尝试过的所有内容)

function getBoard(qrcode) {

    return db.createConnection(dbConfig)
    .then(conn => {
        let rows = conn.query("SELECT * FROM boards WHERE id = ?", [qrcode])
        .then(() => { conn.end() }); // Can't call it here cus it ends conn before rows is set

        conn.end(); // Can't call it here cus rows is still pending

        if (rows.length >= 1)
            return rows[0];

        return null;
    })
    .finally({
        conn.end(); // Can't call it here cus it gets called before the 'then' block in the caller
    });


}

【问题讨论】:

  • let rows = conn.query( rows 永远不会在这里设置.. cus it ends conn before rows is set 不,那是行,只是它会被传递到参数中。
  • IOW:.then((rows) => { /* rows is here*/ conn.end() });

标签: javascript mysql node.js mariadb


【解决方案1】:

conn.query 是异步的,因此then 将完成,finally 将在查询产生任何结果之前触发,即使只需要几毫秒。不管你是在解决 promise,封闭的 promise 会实现,还是链式的 then 会实现。

async function getBoard(qrcode) {
  const conn = await db.createConnection(dbConfig);

  try {
    return await conn.query("SELECT * FROM boards WHERE id = ?", [qrcode]);
  } finally {
    conn.end();
  }
}

提示 - 如果此应用程序持续运行,您只需连接到数据库一次并重用连接,那么就无需为每个查询打开和关闭连接。

【讨论】:

  • 你把这一切搞混了,你使用async / await,然后不要使用它,然后在不需要的时候使用 Promise 构造函数..
  • 不,有问题。你快到了,如果你打算使用async/await 做更多的事情。 async function getBoard(qrcode) { const con = await db.createConnection(dbConfig); const rows = await..... 等。当然还有普通的 javascript try finally 以确保 con.end()
  • 那就更好了,:) 我个人会取出 -> catch { return null; 让异常传播,否则被调用者将不得不进行“空”检查,更糟糕的是仍然不知道为什么他们是一个错误。
  • ps。我也能理解你为什么使用let 来确定范围的原因。但是你不需要它,你可以做 -> const conn = await db.create...,并在这一行之后放置尝试,目前无论如何之前都没有意义,IOW:如果 conn 从未返回,则无法执行 conn.end
  • 对,奇怪的是我忽略了这一点。你今天在你的 cmets 上帮助了我很大,所以谢谢你。我敢肯定,从现在开始我会更有效地解决这些问题!
【解决方案2】:

我认为最好的解决方案是遵循最佳实践... 为了解决您的问题,我认为最好将conn.end(); 与承诺链的finally 部分中的conn.end(); 结合起来,只有当查询顺利或没有待处理的请求时才会触发它。我会这样做:

.finally({
      if(conn){
          conn.end();
      }
 });

显然,您必须从源代码的任何其他部分中删除 conn.end(); 代码行。我什至会考虑使用更多catch() 来检查其他错误。

希望它能帮助我解决你想要的任何问题。

【讨论】:

    【解决方案3】:

    我不建议在每次调用 db 方法后关闭连接。它的效率非常低,您可以使用连接池。更多详情请看这里

    https://www.npmjs.com/package/mysql#pooling-connections

    当所有工作完成后,您可以关闭池中的连接。看到这个

    https://www.npmjs.com/package/mysql#closing-all-the-connections-in-a-pool

    希望这会有所帮助。

    【讨论】:

    • 我已经把这个作为答案,因为我最终选择了泳池解决方案。
    【解决方案4】:
      async function scanBoard(qrCode)
     {
    
          let board = await getBoard(qrCode);
      }
      catch (e)
      {
          throw e;
      }
    
     }
    
    async function getBoard(qrcode)
          {
    
                    let dbConn = await  db.createConnection(dbConfig);
                    let rows = await dbConn.query("SELECT * FROM boards WHERE id = ?", [qrcode]);
                    if (rows.length >= 1)
    
                    // If you need to re-use connection, create a connection instance and re-use.Do not close here
    
                    return rows[0];            
            }
    

    【讨论】:

    • 这不使用承诺
    • 一些事情 -> catch (e) { throw e; 什么都不做。 if(dbConn) 永远是真的。
    • @TedTrippin 是的,确实如此。
    • @Keith 在查询或创建连接时发生错误,我们需要捕获并抛出错误。它与if(dbConn) 无关。你可以摆脱这种情况。它只是在关闭之前保护对象所以我认为它是有效的
    • 不,你不必扔。catch(e) { throw e 是一个空操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-21
    • 2017-01-14
    • 1970-01-01
    • 2019-05-24
    • 2015-01-06
    • 2018-09-19
    相关资源
    最近更新 更多