後端搭起大體的框架後,接著涉及到的就是如何將數據持久化的問題,也就是對資料庫進行 CURD 操作。 關於資料庫方案, mongodb 和 mysql 都使用過,但我選用的是 mysql ,原因: 1. 目前為止 mysql 與 mongodb 性能相差不大,尤其是 mysql 8.0 版本,速度非常 ...
後端搭起大體的框架後,接著涉及到的就是如何將數據持久化的問題,也就是對資料庫進行 CURD 操作。
關於資料庫方案, mongodb 和 mysql 都使用過,但我選用的是 mysql,原因:
- 目前為止 mysql 與 mongodb 性能相差不大,尤其是 mysql 8.0 版本,速度非常快,查詢數據是 mysql 更快,寫數據方面 mongodb 則更勝一籌;
- mysql 建立 關聯數據要更方便些,比如: 一對多,多對多的關係;
- mysql 作為關係型資料庫,數據一致性方面更好,尤其是事務用起來更順手;
- 本人對 sql 操作比較得心應手,畢竟大部分項目用得都是 mysql,而 mongodb 在正式些的項目上用的就少了,而且目前關係型資料庫也在進化, postgrep 和 mysql 都已經支持 json了。
node-mysql
node-mysql 是用 sql 語句對 mysql 進行操作的庫, 並沒有使用 Sequelize 這種 orm。因為我對 sql 熟悉,原生開發效率高。
連接池
連接資料庫我選用 連接池的方式,這種方式能高效的利用資料庫連接
//dbPool.js
const mysql = require('mysql');
const dbconfig = require('../config/db');
const log = require('../common/logger');
let pool = null;
/**
* get the connection pool of database
* 獲取資料庫連接池
*/
exports.getPool = function () {
if (!pool) {
log.info("creating pool");
pool = mysql.createPool(dbconfig);
}
return pool;
}
資料庫配置文件
emoji 格式要用 utf8mb4 格式存儲,所以這裡連接字元集選用 utf8mb4,當然客戶端和數據結果集 一樣也要設置為 utf8mb4。
module.exports={
host: "localhost",
port: "3306",
user: "root",
password: "jeff",
database: "chatdb",
charset : 'utf8mb4',//utf8mb4才能保存emoji
multipleStatements: true,// 可同時查詢多條語句, 但不能參數化傳值
connectionLimit: 100 //連接數量
};
Dao的編寫
基本的代碼編寫方式如下,每個方法基本都是這麼一種流程,獲取資料庫連接,執行 sql 語句,返回結果,處理異常。
exports.queryInfo = function (params, callback){
pool.query('select ...', params, function (error, result, fields) {
if (error) {
log(error);
callback(false);
}
else callback(result)
});
}
exportDao
這造成了一大堆重覆的樣板代碼,我們需要封裝它,用 JavaScript 高階函數特性 很容易就能實現,同時加上 Promise,調用時就能方便地用 async await 了,還有日誌記錄功能也加上。
const pool = require("./dbPool").getPool();
const log = require('../common/logger');
/**
* export named query function
*/
const exportDao = opts => Object.keys(opts).reduce((next, key) => {
next[key] = (...args) => new Promise((resolve, reject) => {
if (opts[key]) args.unshift(opts[key]);
log.info('====== execute sql ======')
log.info(args);
pool.query(...args, (err, result, fields) => {// fields is useless
if (err) reject(err)
else resolve(result);
});
});
return next;
}, {});
userDao文件為例,使用 exportDao 直接就能把裡面的 key-value 對象輸出為 以key 為方法名的dao方法,掛載到 module.exports 下。
const { exportDao } = require('./common');
//直接就exports裡面的key值對應的方法
module.exports = exportDao({
sql: null,// 有些時候需要直接寫sql
count: 'select count(*) as count from user where ?',
getUser: 'select * from user where ?',
insert: 'insert into user set ?',
update: 'update user set ? where id = ?',
delete: 'delete from user where ?'
});
/* 最終輸出格式
module.exports = {
sql:() => {},
count:() => {},
...
}*/
transaction
還有事務 transaction 的功能需要用到,來看一下 node-mysql 官方的例子,層層回調