美文网首页程序员程序园
Node.js中使用mysql时报错Error: Cannot

Node.js中使用mysql时报错Error: Cannot

作者: JabinGP | 来源:发表于2019-04-30 00:50 被阅读2次
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' } ]

相关文章

网友评论

    本文标题:Node.js中使用mysql时报错Error: Cannot

    本文链接:https://www.haomeiwen.com/subject/tnmpnqtx.html