数据持久化 – 通俗地说就是将系统内存中的数据存储到数据库等数据管理工具中, 以及将数据从数据库中取出转换成内存中数据
本篇主要介绍 mysql, redis 两种数据管理工具在node中的使用。
本篇及以后的介绍都将基于第六篇建立的系统结构。
一、redis操作
redis的使用在第二篇 session 一节中有介绍过,本篇在此简单介绍下, 推荐使用node访问redis的中间件: ioredis, ioredis 的使用细节都可以在文档 (REDADME) 中找到。
1、redis连接: 为了避免每次使用redis都去写一段连接的代码,因此有必要 redis 建立链接的过程封装成一个公共 api, 方便使用。
a、首先在配置路径 /config 下的三套环境配置文件中添加 redis 配置数据:
1
2
3
4
5
6 let redisConfig = {
port: 6379, //端口
host: '192.168.1.100', //地址
//password: 'auth', //访问密码
}
module.exports = { redisConfig: redisConfig } //导出
b、连接 redis API, 用于建立 node 与 redisd 的网络连接, 路径 ./src/lib/, 新建文件:redis-connection.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const ioredis = require('ioredis') //引入 ioredis
//根据环境变量选择导入的配置文件
let redisConfig = require('../../config/dev.env.config').redisConfig
if( process.env.NODE_ENV === 'test' ) {
const redisConfig = require('../../config/test.env.config').redisConfig
} else if( process.env.NODE_ENV === 'production' ) {
const redisConfig = require('../../config/prod.env.config').redisConfig
}
//连接redis
let clientCreate = (config, callback_) => {
let redis = new ioredis(config)
redis.on('connect', () => { //根据 connect 事件判断连接成功
callback_(null, redis) //链接成功, 返回 redis 连接对象
})
redis.on('error', (err) => { //根据 error 事件判断连接失败
callback_(err, null) //捕捉异常, 返回 error
})
}
let redisConn = (options) => {
let config = options || redisConfig
return new Promise((resolve, reject) => { //返回API调用方 一个 promise 对象
clientCreate(config, (err, conn) => {
if(err) {
reject(err) //返回 err
}
resolve(conn) //返回连接对象
})
})
}
module.exports = redisConn
2、 使用上面写的API, 实现redis的增/删/改/查 路径 ./src/app/, 新建文件: redis/redis-test.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
const redisConn = require('../../lib/redis-connection.js')
class RedisTest {
constructor() {
this.redis = null
}
connToredis() { //创建连接对象
return new Promise((resolve, reject) => {
if(this.redis) {
resolve(true) //已创建
} else {
redisConn().then(resp => {
this.redis = resp
resolve(true) }
).catch(err => { reject(err) })
}
})
}
setCommand(id, data) { //增/改
if(expire === null || expire === undefined) {
this.redis.set(`test-${id}`, JSON.stringify(data)).then(resp => {
console.log('set', resp)
}).catch(err => {
console.log('err', err)
})
} else {
this.redis.set(`test-${id}`, JSON.stringify(data), 'ex', expire).then(resp => { //ex 为过期时间,单位为 秒
console.log('set', resp)
}).catch(err => {
console.log('err', err)
})
}
}
getCommand(id) { //查
this.redis.get(`test-${id}`).then(resp => {
console.log('get', resp)
}).catch(err => {
console.log('err', err)
})
}
delCommand(id) {
this.redis.del(`test-${id}`).then(resp => {
console.log('resp', resp)
})
}
multiCommand(id, data) {
this.redis.multi().set(`test-${id}`, JSON.stringify(data))
.get(`test-${id}`).exec((err, resp) => {
if(err) {
console.log('err', err)
} else {
console.log('resp', resp)
}
})
}
}
//调用上面的对象,实现redis操作
let redisTest = new RedisTest() //实例对象
redisTest.connToredis().then(resp => { //连接成功后,进行redis操作
if(resp) {
redisTest.setCommand(123456, {name: 'feifeiyu'}) //增
redisTest.getCommand(123456) //查
redisTest.setCommand(123456, {name: 'feifeiyu3'}) //改
redisTest.getCommand(123456)//查
redisTest.delCommand(123456) //删
redisTest.getCommand(123456) //差
redisTest.multiCommand(123457, {name: 'feifeiyu2'})
}
}).catch(err => {
console.log('err', err)
})
setTimeout(() => { //再进行一次redis操作
redisTest.connToredis().then(resp => {
redisTest.setCommand(123458, {name: 'feifeiyu'}, 1) //过期时间 1秒
setTimeout(() => { //等待过期
redisTest.getCommand(123458) //过期返回结果为null
}, 2000)
})
}, 2000)
返回结果
redis 其他功能 订阅, pipeline等功能参见 文档 ioredis
二、mysql操作
MonogoDB 是node最常用的 noSQL 数据库,但是,目前来说 mysql 也是互联网公司使用最广泛的数据库之一。node 通过驱动 mysql 可以实现对mysql数据库的增、删、改、查操作。
安装: npm install –save mysql
注意: 以下内容之介绍node对mysql数据的基本操作,不涉及数据库建库建表等操作
1、 建立mysql连接, 一下只介绍myslq 的 连接池连接(pooling connection)
a、mysql 配置, 路径 ./config/*.env.config.js
1
2
3
4
5
6
7
8
9
10 //mysql连接池连接
let poolConfig = {
host: 'localhost',
port: '3306',
user: 'root',
password: 'mysql123',
database: 'fei',
// connectionLimit: 10,
}
module.exports = { poolConfig: poolConfig }
b、mysql 连接, 路径 ./src/lib/, 新建文件: mysql-connection.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const mysql = require('mysql')
let mysqlConf = require('../../config/dev.env.config').poolConfig
if( process.env.NODE_ENV === 'test' ) {
const mysqlConf = require('../../config/test.env.config').poolConfig
} else if( process.env.NODE_ENV === 'production' ) {
const mysqlConf = require('../../config/prod.env.config').poolConfig
}
let poolCreate = (config, callback_) => {
const pool = mysql.createPool(config) //创建连接
pool.getConnection((err, conn) => {
if(err) {
callback_(err, null) //有错误 回调
} else {
console.log('get connected')
callback_(null, conn) //连接成功回调
}
})
}
let mysqlPool = (options) => {
let config = options || mysqlConf
return new Promise((resolve, reject) => {
poolCreate(config, (err, conn) => {
if(err) {
reject(err) //出错
}
resolve(conn) //成功
})
})
}
module.exports = mysqlPool
c、创建数据表 user
d、dao层创建,即(实现 sql 语句操作), 路径 ./src/dao, 新建文件: mysql-dao.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
const mysqlPool = require('../lib/mysql-connection')
class MysqlTestDao {
constructor() {
this.fieldType = { //数据库中各个字段数据类型
id: 'INT',
nick: 'VARCHAR',
mobile: 'VARCHAR',
family_name: 'VARCHAR',
last_name: 'VARCHAR',
address: 'VARCHAR',
}
}
fieldTypeConfig(param) {
let keys = Object.keys(param)
keys.map(item => { //数据类型配置
try {
if(this.fieldType[item] == 'INT') {
param[item] = Number(param[item])
} else { //主要目的是为字符串数据加上引号
param[item] = '\'' + param[item] + '\''
}
} catch (err) {
return 'type error' + err
}
})
return param
}
queryAll() { //查询所有数据
return new Promise((resolve, reject) => {
mysqlPool().then( conn => {
let sql = 'select * from user;'
conn.query(sql, (err, result) => {
conn.release() //查询结束后释放链接池
if(err) reject(err)
resolve(result)
})
}).catch(err => {
reject(err)
})
})
}
queryById(param) { //根据id查询
return new Promise((resolve, reject) => {
mysqlPool().then( conn => {
let sql = 'select * from user where id=' + param.id + ';'
conn.query(sql, (err, result) => {
conn.release()
if(err) reject(err)
resolve(result)
})
}).catch(err => {
reject(err)
})
})
}
insert(param) { //插入数据
return new Promise((resolve, reject) => {
mysqlPool().then( conn => {
param = this.fieldTypeConfig(param)
if(typeof param === 'string') {
reject(param)
}
let keys = Object.keys(param)
let sql = 'insert into user '
+ '(nick, mobile, family_name, last_name, address) '
+ 'values '
+ '('
keys.map((item, index) => {
if(index === 0) {
sql += param[item]
} else {
sql += ', ' + param[item]
}
})
sql += ');'
conn.query(sql, (err, result) => {
conn.release()
if(err) reject(err)
resolve(result)
})
}).catch(err => {
reject(err)
})
})
}
updateById(param, id) { //更新数据
return new Promise((resolve, reject) => {
mysqlPool().then( conn => {
param = this.fieldTypeConfig(param)
if(typeof param === 'string') {
reject(param)
}
let keys = Object.keys(param)
let sql = 'update user set\ '
keys.map((item, index) => {
if(index === 0) {
sql += item + '=' + param[item]
} else {
sql += ', ' + item + '=' + param[item]
}
})
sql += 'where id=' + id + ';'
console.log('sql', sql)
conn.query(sql, (err, result) => {
conn.release()
if(err) reject(err)
resolve(result)
})
})
})
}
deleteById(id) { //删除数据
return new Promise((resolve, reject) => {
mysqlPool().then( conn => {
let sql = 'delete from user where id=' + id + ';'
console.log('sql', sql)
conn.query(sql, (err, result) => {
conn.release()
if(err) reject(err)
resolve(result)
})
})
})
}
}
module.exports = MysqlTestDao
e、 数据库使用(dao层调用),在业务逻辑目录 ./src/app/ 新建目录 mysqltest, 在 mysql 下新建 mysql-test.js, 加入一下代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const MysqlTestDao = require('../../dao/mysql-dao')
let mysqlTest = new MysqlTestDao()
var newItem = {
nick: 'feifeiyu3',
mobile: '13245654313',
family_name: 'xu',
last_name: 'lu',
address: 'hangzhou',
}
//查询 by id
mysqlTest.queryById({id: 1}).then(resp => {
console.log('query by id', resp)
}).catch(err => {
console.log('err', err)
})
//插入新数据
mysqlTest.insert(newItem).then(resp => {
console.log('inert', resp)
}).catch(err => {
console.log('err', err)
})
//查询所有
mysqlTest.queryAll().then(resp => {
console.log('queryAll', resp)
}).catch(err => {
console.log('err', err)
})
//数据更新
mysqlTest.updateById({nick: 'feifieyu5', mobile: 13256788765}, 2).then(resp => {
console.log('update by id', resp)
}).catch(err => {
console.log('err', err)
})
//数据删除
mysqlTest.deleteById(3).then(resp => {
console.log('delete by id', resp)
}).catch(err => {
console.log('err', err)
})
e 运行脚本,console 进入 mysql-test.js 所在目录, 运行命令 node –harmony mysql-test.js,即可看到相应的操作结果。
总结
本篇主要介绍了 redis 和 myslq 的 连接 API 封装, 数据的增、删、改、查。如果配合上 rest 接口(如 第四篇:koa2-web应用进阶—RESTful api),即可实现我们常用的 http 应用。如站点常见的,用户注册,注销,修改等。