NodeJS Mysql 使用体验

a year

生产过程,是免不了要和数据库打交道的,本博客是 Mysql 数据库,在实际使用过程中,踏了不少异步回调的坑。

连接数据库

使用连接池可以减少部分资源开销,在目前的版本也支持断线重连。

import mysql from 'mysql'

// 使用连接池
const pool = mysql.createPool({
  host: '127.0.0.1', 
  user: 'root',
  password: 'root',
  database:'test',
  port: 3306
})

查询数据

连上数据库之后就可以查询数据了,需要熟悉一点 Mysql 的语法,比如获取首页文章。

export const getPosts = (success, fail) => {
  pool.getConnection(function(err, connection) {
    if (err) {
      console.log(err)
      return fail(err)
    }
    connection.query('SELECT * FROM `posts`', function(err, result) {
      if (err) {
        console.log(err)
        return fail(err)
      }
      success(result)
      // 释放连接
      connection.release()
    })
  })
}

export const postsCount = (success, fail) => {
  pool.getConnection(function(err, connection) {
    if (err) {
      console.log(err)
      return fail(err)
    }
    connection.query('SELECT COUNT(*) AS count FROM `posts`', function(err, result) {
      if (err) {
        console.log(err)
        return fail(err)
      }
      success(result)
      connection.release()
    })
  })
}

这样就可以把很多相似的语句封装成一个 db.js 文件,然后在其他地方调用就可以了。

import * from './db.js'

const posts = db.getPosts(function (posts) {
    const count = db.postsCount(function (count) {
        // 输出页面
    }, function (err) {
        // 错误处理
    })
}, function (err) {
    // 错误处理
})

如果首页还需要其他数据,查询语句越庞大,嵌套的层数就会越多,这个时候维护、错误处理的成本就变高了。本人尝试过的方案一,使用 bluebird Promise 化回调方法:

import Promise from bluebird

const queryAsync = Promise.promisify(pool.query, {context: pool});

queryAsync('SELECT * FROM `posts`').then(function(posts) {
  return queryAsync('SELECT COUNT(*) AS count FROM `posts`')
}).then(function(count){
  // 输出模板
}).catch(function(err){
  err && console.error(err)
})

同样也可以使用 NodeJS 自带的 Promise 来实现这个过程,可以减少很多工作量。本人尝试过的另外一个方案,使用 co 来实现,利用 Generator 函数的特性来处理异步回调。

import co from 'co'

const dbQuery = function(query) {
  return new Promise(function(resolve, reject){
    pool.getConnection(function (err, connection) {
      if (err) {
        reject(err)
      }
      connection.query(query, function (err, result) {
        if( err ){
          reject(err)
        }else{
          resolve(result)
        }
        connection.release()
      })
    })
  })
}

co(function*() {
  const posts = yield dbQuery('SELECT * FROM `posts`')
  const count = yield dbQuery('SELECT COUNT(*) AS count FROM `posts`')
  // 输出模板
}).catch(function(error){
  err && console.error(error)
})

使用 co 可以让解构看上去清晰很多,至于 ES7 中 async/await 的新特性,还没有尝试过,也是解决的方案之一。