koa访问mysql数据库操作 - zhoutk
契机
用restify与express有一年多了,一直在考虑什么时候上koa与es6,看到《一起学koa》项目,决定以此为契机行动起来。首先我要完成的是对数据库操作的封装,将以前项目实践中的代码迁移到koa上来,于是决定先完成《一起学koa》中的mysql任务。
koa基本知识
koa依赖co,最新版基于promise实现。我们使用koa的时候都是通过use添加一个中间件,router也是一个个中间件,我们看一下use都做了什么?
app.use = function(fn){ this.middleware.push(fn); return this;};
它只是将参数保存起来,然后返回引用,最后由co完成调用,因此要求中间件中的异步调用都使用Promise形式。
实现方法一(co-mysql)
mysql库是以回调形式实现的,而koa中间件要求Promise形式,经过搜索,发现了co-mysql和mysql-co,这两个库的思路差不多,mysql-co封装度更高,并使用速度更快的mysql2,而co-mysql更简单,只是将mysql.query封装成Promise形式。下面是基于co-mysql的写法
var wrapper = require('co-mysql'), mysql = require('mysql');var options = { host : 'localhost', port : 3306 , database : 'test', user: 'root', password : 'rootroot'};var pool = mysql.createPool(options), p = wrapper(pool);... var rows = yield p.query('SELECT 1'); yield this.render('index', { title: rows[0].fieldName });...})();
实现方法二(promisify-node)
找到promisify-node库,可以将库整体转化为Promise形式,示例代码如下:
var promisify = require("promisify-node");var db = promisify("myDbHelper");...var rows = yield db.getById('tableName', {id:1}); yield this.render('index', { title: rows[0].fieldName });...
实现方法三(thunkify、thunkify-wrap)
看tj/co说明的Yieldables部分说明如下:
The yieldable objects currently supported are:
promises
thunks (functions)
array (parallel execution)
objects (parallel execution)
generators (delegation)
generator functions (delegation)
因此使用thunkify也能够完成封装,thunkify-wrap是一个增强版的thunkify,不过看说明,这种方法在未来的发展中可能会被淘汰,大概的使用如下:
var genify = require('thunkify-wrap').genify;var db = genify("myDbHelper");...var rows = yield db.getById('tableName', {id:1}); yield this.render('index', { title: rows[0].fieldName });...
实现方法四(直接方法)
直接改造原来express下的代码为Promise形式,参考了co-mysql,并仔细学习了Promise相关知识,完成了已有代码的改造,代码及说明如下:
dbHelper.js
var config = require('./dbconfig');var options = { 'host': config.db_host, 'port': config.db_port, 'database': config.db_name, 'user': config.db_user, 'password': config.db_passwd}var mysql = require('mysql');var pool = mysql.createPool(options);//内部对mysql的封装,执行sql语句function execQuery(sql, values, callback) { var errinfo; pool.getConnection(function(err, connection) { if (err) {errinfo = 'DB-获取数据库连接异常!';throw errinfo; } else {var querys = connection.query(sql, values, function(err, rows) { release(connection); if (err) { errinfo = 'DB-SQL语句执行错误:' + err; callback(err); } else { callback(null,rows); //注意:第一个参数必须为null }}); } });}function release(connection) { try { connection.release(function(error) {if (error) { console.log('DB-关闭数据库连接异常!');} }); } catch (err) {}}//对外接口返回Promise函数形式exports.getById = function(tablename, id){ return new Promise(function(resolve, reject){ var values = {id:id}; var sql = 'select * from ?? where ?'; execQuery(sql,[tablename, values], function(err, rows){if(err){ reject(err);}else{ resolve(rows);} }) });}
routes/index.js
var db = require("../dbHelper");...var rows = yield db.getById('tableName', {id:1}); yield this.render('index', { title: rows[0].fieldName });...
代码
请参考这个项目中的数据库操作部分,项目处于持续开发中,数据库示例部分取自该项目。
https://github.com/zhoutk/koadmin.git
小结
koa框架以co库为核心组织,很好的用generator来解决了回调函数问题。