【问题标题】:Nodejs 12 Callback not working for mysql connection?Nodejs 12回调不适用于mysql连接?
【发布时间】:2020-01-02 20:30:57
【问题描述】:

我正在编写此代码以在 AWS Lambda 中运行。

查看mysql连接文档

如果一切正常且没有错误,我希望收到消息“数据库连接成功!” 然后得到一条消息“connected as id”,但这不是它发生的顺序。这是我的代码。

'use strict';

let mysql = require('mysql');

const connection = mysql.createConnection({
  dateStrings: true,
  host     : process.env.rds_host,
  user     : process.env.rds_user,
  password : process.env.rds_password,
  database : process.env.rds_database,
  port     : process.env.rds_port
});

exports.handler = (event, context, callback) => {
  //prevent timeout from waiting event loop
  context.callbackWaitsForEmptyEventLoop = false;

  let sql = 'SELECT * FROM company ORDER BY points DESC, name ASC';
  let data = null;
  console.log('\nGetCompanies SQL: ', sql);
  let responseBody = "";
  let statusCode   = 0;

  connection.connect(function(err) {
  if (err) {
      statusCode = 500;
      responseBody = err;
    }
    else{
      console.log("Database connected successfully!");
      statusCode = 200;
      responseBody = "Database connected successfully!";
    }
  });
  console.log('connected as id ' + connection.threadId);

  connection.query(sql, data, function(queryError, results) {
    if(queryError) {
      console.error(queryError.message);
      callback(queryError);
    }
    else
    {
      console.log('\nGetCompanies Results: ', results[0]);
      callback(null, results);
    }
  });
};

这是记录的输出:

信息
GetCompanies SQL: SELECT * FROM company ORDER BY points DESC, name ASC 2020-01-01T11:52:57.813Z

INFO connected as id null 2020-01-01T11:52:57.952Z

INFO 数据库连接成功! 2020-01-01T11:52:57.974Z

我的想法是我提供的功能:

connection.connect(function(err) {

将在connection.connect之后的任何代码之前执行。我这样想有错吗?

还有一个问题:为什么是

连接为 id null?我直接从mysql 文档中获得了该代码(connection.threadId)。

我知道这没什么大不了的,如果它影响的只是日志消息的顺序,但我还有其他功能我无法进行查询,因为连接还不存在。

当它吹过时会很混乱

if (err) {
  statusCode = 500;
  responseBody = err;
}
else{
  <do some connection.query code here>
}

我把这些日志信息放在这里是因为这个方法有效,而我的其他方法无效。

【问题讨论】:

    标签: mysql node.js aws-lambda


    【解决方案1】:

    您出现这种行为是因为 console.log('connected as id ' + connection.threadId); 没有等待 connection.connect 完成连接。

    你需要在这里使用promises

    您可以尝试使用async/await

    exports.handler = async (event, context, callback) => {
        //prevent timeout from waiting event loop
        context.callbackWaitsForEmptyEventLoop = false;
    
        let sql = 'SELECT * FROM company ORDER BY points DESC, name ASC';
        let data = null;
        console.log('\nGetCompanies SQL: ', sql);
        let responseBody = "";
        let statusCode   = 0;
    
        try {
            await connection.connect();
    
            console.log("Database connected successfully!");
            console.log('connected as id ' + connection.threadId);
    
            const queryResult = await connection.query(sql, data);
    
            // do something with queryResult
        } catch (e) {
            // handle error
        }
    };
    

    编辑

    您链接到的资源建议在回调上使用承诺:

    等待任何承诺而不是使用回调

    【讨论】:

      【解决方案2】:
      would execute before any code after connection.connect. Am I wrong to think that?
      
      • 您传递给connection.connect 的函数称为 回调函数。这意味着,它只会在之后被调用 成功连接(或连接尝试出错后)。所以答案是否定的。 connection.connect 被调用,然后它会立即调用下一条语句。它不会等待当前语句,因为 javascript 是事件驱动且非阻塞的。

      连接为 id null?我直接从 mysql 文档中获得了该代码(connection.threadId)。

      • 这是因为前面的语句,您在获取连接之前记录了 connectionId。

      使用回调

      您的代码应如下所示。我没有做太多修改,只有在调用了connect事件的回调后才建立与数据库的连接。

      exports.handler = (event, context, callback) => {
        //prevent timeout from waiting event loop
        context.callbackWaitsForEmptyEventLoop = false;
      
        let sql = 'SELECT * FROM company ORDER BY points DESC, name ASC';
        let data = null;
        console.log('\nGetCompanies SQL: ', sql);
        let responseBody = "";
        let statusCode = 0;
      
        connection.connect(function (err) {
      
          // we are inside the callback function a successful connection has been obtained , or error connecting to database
          if (err) {
            statusCode = 500;
            responseBody = err;
          }
          else {
            console.log("Database connected successfully!");
            statusCode = 200;
            responseBody = "Database connected successfully!";
          }
      
          // connection exists
          console.log('connected as id ' + connection.threadId);
      
          connection.query(sql, data, function (queryError, results) {
            if (queryError) {
              console.error(queryError.message);
              callback(queryError);
            }
            else {
              console.log('\nGetCompanies Results: ', results[0]);
              callback(null, results);
            }
          });
        });
      };
      

      使用承诺

      如果您可以使用 Promise 使您的代码具有可读性和可理解性。

      import { promisify } from 'util';
      exports.handler = async (event, context) => {
        //prevent timeout from waiting event loop
        context.callbackWaitsForEmptyEventLoop = false;
      
        let sql = 'SELECT * FROM company ORDER BY points DESC, name ASC';
        let data = null;
        console.log('\nGetCompanies SQL: ', sql);
      
        const connect = promisify(connection.connect);
        const query = promisify(connection.query);
      
        try {
          const connection = await connect();
      
          // connection exists
          console.log('connected as id ' + connection.threadId);
          const results= await query(sql);
      
          return {
            statusCode: 200,
            responseBody: JSON.stringify(results)
          }
      
        } catch (err) {
          return {
            statusCode: 500,
            responseBody: err.message
          }
        }
      };
      

      【讨论】:

      • 好的,知道了。 :-) 感谢您的快速回复。所以连接后我想做的所有事情都需要在连接回调中。或用承诺处理。
      • @arun-k 如果您使用其他人的部分答案至少引用他们,这是习惯性的:)
      • @KingAndrew 正确。使用回调没有错。只是 async/await 是干净的。注意 util.promisify 的用法。它很方便,因为它用于将回调转换为承诺
      • @T.Short 很抱歉你有这种感觉。但事实并非如此。我认为您在谈论承诺部分。如果你仔细看,我使用 typescript 进行导入,也使用 promisify。如果您的意思是我使用了您的答案,那不是真的,因为您正在等待connection.connect。您不能等待带有回调的语句。
      • @ArunK 我需要在查询(sql)前面等待吗?如果不是为什么?
      【解决方案3】:

      您应该将您的 connection.query 语句移动到 connection.connect 范围内,因为即使您无法连接到数据库,您也会尝试进行无法正常工作的查询。

      exports.handler = (event, context, callback) => {
        //prevent timeout from waiting event loop
        context.callbackWaitsForEmptyEventLoop = false;
      
        let sql = 'SELECT * FROM company ORDER BY points DESC, name ASC';
        let data = null;
        console.log('\nGetCompanies SQL: ', sql);
        let responseBody = "";
        let statusCode   = 0;
      
        connection.connect(function(err) {
        if (err) {
            statusCode = 500;
            responseBody = err;
          }
          else{
            console.log("Database connected successfully!");
            statusCode = 200;
            responseBody = "Database connected successfully!";
            connection.query(sql, data, function(queryError, results) {
              if(queryError) {
                console.error(queryError.message);
                callback(queryError);
              }
              else
              {
                console.log('\nGetCompanies Results: ', results[0]);
                callback(null, results);
              }
            });
          }
        });
        console.log('connected as id ' + connection.threadId);
      
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-02-14
        • 2017-09-28
        • 2018-05-26
        • 2016-03-21
        • 1970-01-01
        • 2020-10-12
        • 2018-02-20
        • 1970-01-01
        相关资源
        最近更新 更多