Node.js中使用mysql时报错Error: Cannot enqueue Query after invoking quit.的解决方法

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' } ]
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 10,995评论 0 9
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 13,902评论 1 32
  • 今天看到一位朋友写的mysql笔记总结,觉得写的很详细很用心,这里转载一下,供大家参考下,也希望大家能关注他原文地...
    信仰与初衷阅读 10,183评论 0 30
  • 从哪说起呢? 单纯讲多线程编程真的不知道从哪下嘴。。 不如我直接引用一个最简单的问题,以这个作为切入点好了 在ma...
    Mr_Baymax阅读 7,818评论 1 17
  • 昨天和一个朋友聊天,不知不觉的聊到时间。说这一年又快过去了。我对时间向来敏感,特别是一到暑假,我就感觉这一年又要过...
    小蓝儿阅读 1,400评论 0 0

友情链接更多精彩内容