我可以理解,每个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>
都需要连接费用。
答案 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;池的列表。这就是连接池通常的工作方式。