node.js async/await 与 MySQL 一起使用

Posted

技术标签:

【中文标题】node.js async/await 与 MySQL 一起使用【英文标题】:node.js async/await using with MySQL 【发布时间】:2017-10-15 17:02:20 【问题描述】:

我需要同步所有结果并附加到带有 async/await 关键字(如 c#)的字符串。

我是 node.js 的新手,我无法将这种新语法适应我的代码。

var string1 = '';
var string2 = '';
var string3 = '';
var string4 = '';

DatabasePool.getConnection(function(err, connection) 

        connection.query(query,function (err, result) 
            if (err);
            string1 = result;
        );

        connection.query(query,function (err, result) 
            if (err);
            string2 = result;
        );     

        connection.query(query,function (err, result) 
            if (err);
            string3 = result;   
        );

        connection.query(query,function (err, result) 
            if (err);
            string4 = result;
        ); 

       //I need to append all these strings to appended_text but  
       //all variables remain blank because below code runs first.
       var appended_text = string1 + string2 + string3 + string4;
);

【问题讨论】:

刚刚检查,您使用的是支持异步/等待的节点版本,对吗? 是的最新版本。 【参考方案1】:

假设你使用的 ORM 是基于 Promise 的,你可以做这样的事情

async function buildString() 
  try 
    const connection = await DatabasePool.getConnection();
    const string1 = await connection.query(query);
    const string2 = await connection.query(query);
    const string3 = await connection.query(query);
    const string4 = await connection.query(query);

    return string1 + string2 + string3 + string4;
   catch (err) 
    // do something
  

通过将await 放在调用前面,任何promise 都可以与async/await 一起使用。但是,请注意 this 函数必须在 async 函数“包装器”中使用。您需要处理try/catch 块中的错误。

我还想指出,这 4 个查询不是同时运行的。你仍然需要为此使用 Promise.all。

【讨论】:

注意 await 只能在异步方法中使用。 谢谢@WilcoBakker。我实际上只是在编辑我的答案:) 我使用mysql包。我认为这不是基于promise的?我应该使用哪个mysql包? 有很多,所以我认为您可能需要一些时间来探索权衡。你可能会遇到的一些是:objection.js、bookshelf、sequelize 如何从查询中获取返回的行值而不是获取字符串?【参考方案2】:

您必须确保您使用的 mysql 库支持 async/await 所需的 Promises,或者使用像 Bluebird's promisifyAll 这样的工具来包装库。

async function appendedText() 
  const connection = await DatabasePool.getConnectionAsync();
  const [string1, string2, string3, string4] = await [
    connection.query(query1),
    connection.query(query2),
    connection.query(query3),
    connection.query(query4),
  ];
  return string1 + string2 + string3 + string4;

请注意,调用 appendedText() 实际上会返回一个 Promise 而不是一个值。

appendedText().then(appended_text => );

【讨论】:

你真的可以像这样使用 await 来模仿 Promise.all 吗?任何想法我可以在哪里找到更多信息,因为我的快速谷歌搜索返回了非常复杂的方法。 @adam-beck,它工作了一段时间......不过现在它需要一个Promise.all()。见这里:***.com/questions/34382710/…【参考方案3】:

使用mysql2数据包。它具有承诺包装器,因此您可以这样做:

async function example1 () 
  const mysql = require('mysql2/promise');
  const conn = await mysql.createConnection( database: test );
  let [rows, fields] = await conn.execute('select ?+? as sum', [2, 2]);

【讨论】:

这是最好的答案......圣牛 Mysql2 比 mysql快得多,并且提供了大量 mysql 没有的东西,比如 promises、压缩和准备好的语句。 使用 await conn.end() 执行查询后不要忘记结束连接;或者更好地使用池而不是像 createPool 和 end pool 这样的连接。 这应该是公认的答案,因为 mysql 现在已弃用,mysql2 至今仍在维护并支持异步 我有点困惑,我需要为每个查询创建与 MySQL 的连接还是将 conn 设为全局并在所有路由中使用? https://npmcompare.com/compare/mysql,mysql2 --> mysql2 是一个更好的包,而且它有更多意义的完整错误消息,这个比较不会告诉【参考方案4】:

您似乎使用了mysqljs,它不是基于承诺的库。所以你不能使用这个库来实现你想要的。所以你可以做的是使用一个基于承诺的库,比如Sequelize,或者按照评论的建议:

使用 Bluebird 的 promisifyAll 之类的工具来包装库。

我对包装的东西不太了解,所以我所做的就是切换到续集。

【讨论】:

【参考方案5】:

如果您恰好在 Node 8+ 中,则可以将原生 util.promisify() 与节点 mysql 结合使用。

不要忘记用bind() 调用它,这样this 就不会搞砸了:

const mysql = require('mysql'); // or use import if you use TS
const util = require('util');
const conn = mysql.createConnection(yourHOST/USER/PW/DB);

// node native promisify
const query = util.promisify(conn.query).bind(conn);

(async () => 
  try 
    const rows = await query('select count(*) as count from file_managed');
    console.log(rows);
   finally 
    conn.end();
  
)()

【讨论】:

感谢关于添加绑定的说明。我花了太长时间试图弄清楚为什么我在使用 Promisify 时遇到问题。 非常感谢有关正确绑定方法的提示 如果我必须为查询函数提供 2 个参数,打字稿会给出错误“预期 1 个参数”。我使用了两个参数,因为查询字符串包含?。有没有办法避免在单个查询字符串中附加第二个参数? 对于打字稿:const 查询:(arg1: string, arg2?: string[])=>Promise = promisify(db.query).bind(db); mysql-async-simple 包为您完成了这项工作。【参考方案6】:

如果您想使用 mysql(也称为 mysqljs),如果您不想使用包装器,则必须做一些工作。但这很容易。下面是连接函数的样子:

const mysql = require('mysql')

var my_connection = mysql.createConnection( ... )

async function connect()

    try
    
        await new Promise((resolve, reject) => 
            my_connection.connect(err => 
                return err ? reject(err) : resolve()
            )
        )
    
    catch(err)
    
        ...handle errors...
    


connect()

如您所见,await 将知道如何处理一个 Promise。您创建此类并在回调实现中使用解析/拒绝函数。这就是它的全部内容,真的,所以使用包装器可能有点多,除非你经常访问你的数据库。

【讨论】:

【参考方案7】:

或者使用mysql-async-simple

https://www.npmjs.com/package/mysql-async-simple

const  makeDb  = require('mysql-async-simple');
const mysql = require("mysql");
 
const connection = mysql.createConnection(
    host: process.env.HOST,
    user: process.env.USER,
    password: process.env.PASSWORD,
    database: process.env.DB
);
const db = makeDb();
await db.connect(connection);
 
try 
    const users = await db.query(connection, 'SELECT * FROM users');
 catch (e) 
    // handle exception
 finally 
    await db.close(connection);

【讨论】:

【参考方案8】:

您可以像这样使用promise-mysql 包:

const mysql = require('promise-mysql')

const getDbConnection = async () => 
  return await mysql.createConnection(
    host: process.env.HOST,
    user: process.env.USER,
    password: process.env.PASSWORD,
    database: process.env.DB
  )


const getUsers = async () => 
  const db = await getDbConnection()
  const users = await db.query("SELECT * FROM users")
  await db.end()
  return users


【讨论】:

【参考方案9】:

正如LeOn - Han Li 所说,我包含了一些小的修改,因为我必须处理结果。

var mysql = require('mysql');
const util = require('util');

const conn = mysql.createConnection(
  host     : '127.0.0.1',
  user     : 'user',
  password : 'password',
  database : 'database'
);

const query = util.promisify(conn.query).bind(conn);

let result = async function() 
    var userCourse = [];
    try 
        const rows = await query('select * as count from file_managed');
     finally 
        conn.end();
        return userCourse;
    
;

result()
.then(value => 
    console.log(value)
);

【讨论】:

【参考方案10】:

我们可以在 mysql.connect

中实现 promise,而不是使用 utilpromise/mysql

var con = require('mysql');

var mysql = con.createConnection(
    host: "localhost",
    user: "root",
    password: "pass",
    database: "test"
);

async function asyncAwait(req, res) 
    var promise1;
    mysql.connect((err) => 
        promise1 = new Promise((resolve, reject) => 
            console.log('Mysql: Connected');
            resolve(response.write(uc.upperCase('Connected\n')));
        );
        promise1
            .then(() => 
             //Implement the logic here
            )
            .catch(error => 
                console.log(error)
            );
    )

await asyncAwait();

【讨论】:

以上是关于node.js async/await 与 MySQL 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 7 的 async await 终于来了,不过怎么觉得没啥用

Node.js回调地狱及使用Promiseasync和await函数的解决方法

Node.js 最佳实践异常处理——在 Async/Await 之后

Node.js 使用 async/await 读取文件

理解 Node JS 中的 async/await

在 Node.js 中使用 async/await 正确处理错误