Error: Cannot enqueue Query after invoking quit.
at Protocol._validateEnqueue (/Users/jabingp/Github/CodeSharing/node_modules/mysql/lib/protocol/Protocol.js:215:16)
at Protocol._enqueue (/Users/jabingp/Github/CodeSharing/node_modules/mysql/lib/protocol/Protocol.js:138:13)
at Connection.query (/Users/jabingp/Github/CodeSharing/node_modules/mysql/lib/Connection.js:201:25)
at Query.<anonymous> (/Users/jabingp/Github/CodeSharing/dist/backEnd/db/DB.js:86:34)
at Query.<anonymous> (/Users/jabingp/Github/CodeSharing/node_modules/mysql/lib/Connection.js:525:10)
at Query._callback (/Users/jabingp/Github/CodeSharing/node_modules/mysql/lib/Connection.js:491:16)
at Query.Sequence.end (/Users/jabingp/Github/CodeSharing/node_modules/mysql/lib/protocol/sequences/Sequence.js:83:24)
at Query._handleFinalResultPacket (/Users/jabingp/Github/CodeSharing/node_modules/mysql/lib/protocol/sequences/Query.js:139:8)
at Query.OkPacket (/Users/jabingp/Github/CodeSharing/node_modules/mysql/lib/protocol/sequences/Query.js:72:10)
at Protocol._parsePacket (/Users/jabingp/Github/CodeSharing/node_modules/mysql/lib/protocol/Protocol.js:291:23)
出错代码如下
updateDatas(datas:Array<any>){
this.connect();
console.log("要修改的数据:")
console.log(datas);
for(let data of datas){
this.connection.query(`update test set name = "${data.name}" where id = ${data.id}`,(error, results) =>{
if (error) throw error;
console.log(results);
this.connection.query('SELECT * from test', function (error, results, fields) {
if (error) throw error;
console.log("查询结果是");
console.log(results);
});
});
}
this.end();
}
这段代码我想完成的事情是每次更新后都查询所有的值,输出一下每个值的当前状态,然后执行完所有查询就把数据库关闭。
解决方案
从错误中可以看出来大概是数据库以及关闭了,但代码却执行了数据库操作,我们把最下面的this.end()去掉,代码就成功执行了,或者在代码运行的其他阶段执行this.end(),避免数据库连接关闭的情况下执行数据库查询操作。
执行结果
更改数据
要修改的数据:
[ { name: 'change Hello World again', id: 4 },
{ name: 'change Hellow JabinGP again', id: 5 } ]
connected as id 285992
OkPacket {
fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: '(Rows matched: 1 Changed: 0 Warnings: 0',
protocol41: true,
changedRows: 0 }
OkPacket {
fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: '(Rows matched: 1 Changed: 0 Warnings: 0',
protocol41: true,
changedRows: 0 }
查询结果是
[ RowDataPacket { id: 4, name: 'change Hello World again' },
RowDataPacket { id: 5, name: 'change Hellow JabinGP again' } ]
查询结果是
[ RowDataPacket { id: 4, name: 'change Hello World again' },
RowDataPacket { id: 5, name: 'change Hellow JabinGP again' } ]
结果并不是预想的输出一个插入结果后输出一个查询结果,而是两个插入结果先输出后输出两个查询结果,为什么?下面进行个人的推测分析。
原因分析
错误分析
我在前面的文章https://www.jianshu.com/p/59fda67a868e
提到过,connection关闭时并不会直接关闭,而是会将任务队列中的任务都执行完才关闭,而回调是任务执行成功或者失败后调用的,关闭连接时的确会检查任务队列,但是回调函数不在任务队列中,也就是说回调函数里面的:
this.connection.query('SELECT * from test', function (error, results, fields) {
if (error) throw error;
console.log("查询结果是");
console.log(results);
});
这个部分不会被识别为任务队列,所以系统并不会知道这个任务是要再关闭数据库之前执行的,系统仅仅只是确保了循环中的"insert xxx" 会在被关闭连接前执行,但不保证回调中"select * xxx"会在关闭连接前执行,于是在执行这个语句之前数据库连接就关闭了,导致报错。
结果为何不理想
由于for循环执行极快(对比使用网络请求数据库),两个插入操作几乎是同时进入任务队列然后先后执行,执行两个插入操作后此时任务队列为空,不执行任何数据库操作,等待插入操作成功后,输出完两个的结果,代码才执行到查询操作,查询操作才进入任务队列,随后才回调输出查询结果,所以是两个插入先依次输出,两个查询后依次输出。
验证分析
因为node中的mysql是异步的,但是有任务队列机制,我们将查询部分的代码拉出回调,改为和插入并列,这样由于队列机制,执行上也是有先后顺序的,所以能达到我想要的效果:
updateDatas(datas:Array<any>){
this.connect();
console.log("要修改的数据:")
console.log(datas);
for(let data of datas){
this.connection.query(`update test set name = "${data.name}" where id = ${data.id}`,(error, results) =>{
if (error) throw error;
console.log(results);
});
this.connection.query('SELECT * from test', (error, results, fields)=> {
if (error) throw error;
console.log("查询结果是");
console.log(results);
});
}
this.end();
}
执行结果:
更改数据
要修改的数据:
[ { name: 'change Hello World again', id: 4 },
{ name: 'change Hellow JabinGP again', id: 5 } ]
connected as id 285986
OkPacket {
fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: '(Rows matched: 1 Changed: 0 Warnings: 0',
protocol41: true,
changedRows: 0 }
查询结果是
[ RowDataPacket { id: 4, name: 'change Hello World again' },
RowDataPacket { id: 5, name: 'change Hellow JabinGP again' } ]
OkPacket {
fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: '(Rows matched: 1 Changed: 0 Warnings: 0',
protocol41: true,
changedRows: 0 }
查询结果是
[ RowDataPacket { id: 4, name: 'change Hello World again' },
RowDataPacket { id: 5, name: 'change Hellow JabinGP again' } ]
网友评论