pool.query() 和 pool.getGetConnection() 在 connection.release() 上有何不同?
How does pool.query() and pool.getGetConnection() differ on connection.release()?
据我所知,每个 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..
});
});
});
UPDATE
这是我在执行嵌套查询时使用事务的代码。
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()
因为此时我不知道如何正确释放每个处于活动状态的连接。
而且我还假设 pool.getConnection()
中的每个 con.query()
都需要一个连接。
我不知道 Node.js,但查看代码和 Github 文档,几乎可以肯定 pool.getConnection 从连接池获取连接并调用获取连接对象的函数以及从池中获取连接时遇到的任何错误。在函数体中,我们可以多次使用连接对象,但是一旦它被释放,它将无法使用,因为它返回到池中,我假设连接对象将不再引用底层 mysql 连接(可能是低级别的连接对象)。现在我们只需要释放连接对象一次,如果我们不想运行从连接池中取出空闲连接,就必须释放连接对象;否则后续调用 pool.getConnection 将不会在 "free" 连接列表中找到任何连接,因为它们已经移动到 "in_use" 连接列表并且它们永远不会被释放。
一般情况下,从连接池中得到一个连接后,可能会用于任意数量的operations/queries释放"once"返回给"free"列表的水池。这就是连接池通常的工作方式。
听起来您没有尽快关闭第一个查询。
请向我们展示实际代码。您无需等待 查询 即可获得 insertid
.
(问题更新后:)我不明白 "nesting" 的必要性。代码是线性的(抛出错误除外):
BEGIN;
INSERT ...;
get insertid
UPDATE ...;
COMMIT;
如果任何步骤失败,抛出错误。我认为不需要两个 "connections"。在开始 UPDATE
之前,您已经完成了 INSERT
,因此我认为不需要 "nesting" SQL 命令。而 get insertid
是一个元操作,不涉及真正的 SQL 命令。
编辑:
A connection
就像一根电线,将您的应用程序连接到数据库。每次你 connection.query()
你所做的只是通过那条线路发送一条消息,而不是更换线路。
当您向 pool
请求 connection
时,它会为您提供一个已经存在的 'wire' 或创建一个新的数据库连接。当您 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;
据我所知,每个 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..
});
});
});
UPDATE
这是我在执行嵌套查询时使用事务的代码。
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()
因为此时我不知道如何正确释放每个处于活动状态的连接。
而且我还假设 pool.getConnection()
中的每个 con.query()
都需要一个连接。
我不知道 Node.js,但查看代码和 Github 文档,几乎可以肯定 pool.getConnection 从连接池获取连接并调用获取连接对象的函数以及从池中获取连接时遇到的任何错误。在函数体中,我们可以多次使用连接对象,但是一旦它被释放,它将无法使用,因为它返回到池中,我假设连接对象将不再引用底层 mysql 连接(可能是低级别的连接对象)。现在我们只需要释放连接对象一次,如果我们不想运行从连接池中取出空闲连接,就必须释放连接对象;否则后续调用 pool.getConnection 将不会在 "free" 连接列表中找到任何连接,因为它们已经移动到 "in_use" 连接列表并且它们永远不会被释放。
一般情况下,从连接池中得到一个连接后,可能会用于任意数量的operations/queries释放"once"返回给"free"列表的水池。这就是连接池通常的工作方式。
听起来您没有尽快关闭第一个查询。
请向我们展示实际代码。您无需等待 查询 即可获得 insertid
.
(问题更新后:)我不明白 "nesting" 的必要性。代码是线性的(抛出错误除外):
BEGIN;
INSERT ...;
get insertid
UPDATE ...;
COMMIT;
如果任何步骤失败,抛出错误。我认为不需要两个 "connections"。在开始 UPDATE
之前,您已经完成了 INSERT
,因此我认为不需要 "nesting" SQL 命令。而 get insertid
是一个元操作,不涉及真正的 SQL 命令。
编辑:
A connection
就像一根电线,将您的应用程序连接到数据库。每次你 connection.query()
你所做的只是通过那条线路发送一条消息,而不是更换线路。
当您向 pool
请求 connection
时,它会为您提供一个已经存在的 'wire' 或创建一个新的数据库连接。当您 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;