pool.query()和pool.getGetConnection()在connection.release()上有何不同?

时间:2017-10-26 03:22:22

标签: mysql node.js connection-pooling node-mysql

我可以理解,每个pool.query()将花费一个连接,它会在结束时自动释放。基于github issue的评论。但是使用pool.getConnection()执行嵌套查询呢?

pool.getConnection(function(err, connection) {

  // First query
  connection.query('query_1', function (error, results, fields) {

    // Second query
    connection.query('query_2', function (error, results, fields) {

          // Release the connection
          // DOES THIS ALSO RELEASE query_1?
          connection.release();

          if (error) throw error;

          // you can't use connection any longer here..
    });
  });
});
  

更新

这是执行嵌套查询时使用事务的代码。

const pool = require('../config/db');

function create(request, response) {
   try {

       pool.getConnection(function(err, con) {

           if (err) {
               con.release();
               throw err;
           }

           con.beginTransaction(function(t_err) {

               if (t_err) {
                   con.rollback(function() {
                      con.release();
                      throw t_err;
                   });
               }


               con.query(`insert record`, [data], function(i_err, result, fields){

                   if (i_err) {
                       con.rollback(function() {
                           con.release();
                           throw i_err;
                       });
                   }


                   // get inserted record id.
                   const id = result.insertId;

                   con.query(`update query`, [data, id], function(u_err, result, fields)=> {

                       if (u_err) {
                          con.rollback(function() {
                             con.release();
                             throw u_err;
                          });
                       }

                       con.commit(function(c_err){
                          if (c_err) {
                             con.release();
                             throw c_err;
                          }
                       });

                       con.release();

                       if (err) throw err;

                       response.send({ msg: 'Successful' });
                   });
               });

           });
       });

   } catch (err) {
      throw err;
   }
}

我做了很多防御性错误捕获和con.release(),因为此时我不知道如何正确释放所有处于活动状态的连接。

而且我还假设con.query()pool.getConnection()内的每个<local:IconImage Icon="Shutdown" Colour="CornflowerBlue"> <local:IconImage.Source> <DrawingImage> <DrawingImage.Drawing> <DrawingGroup> <DrawingGroup.Children> <DrawingGroup> <DrawingGroup.Children> <GeometryDrawing Brush="{x:Null}"> <GeometryDrawing.Pen> <Pen Brush="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:IconImage}}, Path=Colour, UpdateSourceTrigger=PropertyChanged}" Thickness="2" /> </GeometryDrawing.Pen> <GeometryDrawing.Geometry> <PathGeometry FillRule="Nonzero" Figures="M8.332,4.941C5.759,6.271 4,8.956 4,12.052 4,16.47 7.582,20.052 12,20.052 16.418,20.052 20,16.47 20,12.052 20,8.911 18.19,6.193 15.555,4.884" /> </GeometryDrawing.Geometry> </GeometryDrawing> <GeometryDrawing Brush="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:IconImage}}, Path=Colour, UpdateSourceTrigger=PropertyChanged}" Pen="{x:Null}"> <GeometryDrawing.Geometry> <RectangleGeometry RadiusX="0" RadiusY="0" Rect="11,2,2,10" /> </GeometryDrawing.Geometry> </GeometryDrawing> </DrawingGroup.Children> <DrawingGroup.ClipGeometry> <RectangleGeometry Rect="0,0,24,24" /> </DrawingGroup.ClipGeometry> </DrawingGroup> </DrawingGroup.Children> </DrawingGroup> </DrawingImage.Drawing> </DrawingImage> </local:IconImage.Source> </local:IconImage> 都需要连接费用。

3 个答案:

答案 0 :(得分:4)

编辑:

connection类似于将应用程序连接到数据库的连线。每当你connection.query()所做的一切就是沿着那条线发送信息时,你就不会更换电线。

当您向pool询问connection时,它会为您提供已经存在的“电汇”,或者为数据库创建新的电汇。当您release()池连接时,池会回收它,但会在一段时间内将其保留到位,以防您再次需要它。

因此query是连接线上的消息。您可以根据需要发送尽可能多的消息,它只有一条线。

原始答案

pool.query(statement, callback)基本上是

const query = (statement, callback) => {
    pool.getConnection((err, conn) => {
        if(err) {
            callback(err);    
        } else {
            conn.query(statement, (error, results, fields) => {
                conn.release();
                callback(error, results, fields);
            });
        }
    })
}

理想情况下,您不应该担心连接数量与您正在进行的往返旅行次数一样多。您可以在构建池时在池配置multipleStatements: true中启用多个语句,然后利用事务。

BEGIN;
INSERT ...;
SELECT LAST_INSERT_ID() INTO @lastId;
UPDATE ...;
COMMIT;

答案 1 :(得分:1)

听起来你没有尽快关闭第一个查询。

请告诉我们实际的代码。您无需挂在查询上即可获取insertid

(更新问题后:)我不明白“嵌套”的必要性。代码是线性的(抛出错误除外):

BEGIN;
INSERT ...;
get insertid
UPDATE ...;
COMMIT;

如果任何步骤失败,则抛出错误。我认为不需要两个“连接”。在启动INSERT之前,您已完成UPDATE,因此我认为不需要“嵌套”SQL命令。 get insertid是一个不涉及真正SQL命令的元操作。

答案 2 :(得分:0)

我不知道Node.js,但是查看代码和Github文档,几乎可以肯定pool.getConnection从连接池获取连接,并且它使用获得的连接对象调用该函数从池中获取连接时遇到错误。在函数体内,我们可以多次使用连接对象,但是一旦它被释放它就不会被用,因为它会回到池中,我认为连接对象将不再具有对底层mysql的引用连接(可能是一个较低级别的连接对象)。现在我们只需要释放一次连接对象,如果我们不想从连接池中用完自由连接,我们必须释放连接对象。否则后续调用pool.getConnection在&#34; free&#34;中找不到任何连接。连接列表,因为它们已经移动到&#34; in_use&#34;连接列表,它们永远不会发布。

通常,在从连接池获得连接后,它可以用于任意数量的操作/查询,并且它会被释放&#34;一次&#34;把它还给&#34;免费&#34;池的列表。这就是连接池通常的工作方式。