安装MySQL驱动
# 全局安装mysql
$ npm i -g mysql
node-mysql2
是node-mysql
的扩展,相比而言mysql2更为人性化。
# 当前项目安装mysql2
$ npm i --save mysql2
- mysql2具有更高的性能
- mysql2支持PreparedStatement多次查询性能更高书写SQL更为简单
- mysql2自带Promise包装器可直接使用async/await语法
- mysql2绝大部分api与mysql库兼容
创建连接
const mysql = require("mysql");
//数据库连接配置
let config = {};
config.host = "127.0.0.1";
config.port = 3306;
config.user = "root";
config.password = "root";
config.database = "test";
//创建数据库连接
const connection = mysql.createConnection(config);
//连接数据库
connection.connect();
连接配置
参数 | 描述 |
---|---|
debug | 是否开启调试模式,默认false。 |
host | 主机地址,默认localhost |
port | 主机端口,默认3306 |
user | 用户名 |
password | 密码 |
database | 数据库名称 |
charset | 连接字符集,默认UTF8_GENERAL_CI 注意需大写 |
timezone | 时区,默认local |
connectTimeout | 连接超时毫秒,默认不限制。 |
localAddress | 可选,本地地址,此IP地址用于TCP连接。 |
socketPath | 连接到UNIX域路径,使用host和port时会被忽略。 |
stringifyObjects | 是否序列化对象 |
typeCast | 是否将列值转化为本地JavaScript类型值,默认true。 |
queryFormat | 自定义query查询语句格式化方法 |
supportBigNumbers | 数据库支持bigint或decimal类型列时需设置,默认false。 |
bigNumberString | supportBigNumbers和bigNumberStrings启动后强制bigint或decimal列以JavaScript字符串类型返回,默认false。 |
dateStrings | 强制timestamp/datetime/date类型数据以字符串类型返回,而非JavaScript Date类型,默认false。 |
multipleStatements | 是否允许一个query查询中拥有多个MySQL语句,默认false。 |
flags | 用于修改连接标识 |
ssl | 使用SSL参数或包含SSL配置文件名称的字符串 |
例如:创建数据库连接并执行查询
$ vim mysql.js
const mysql = require("mysql");
const dbcfg = {
host:"127.0.0.1",
port:3306,
user:"root",
password:"root",
database:"pomelo"
};
const connection = mysql.createConnection(dbcfg);
connection.connect((err)=>{
if(err){
console.error("mysql connect error:%s", err);
}else{
console.log("mysql connect success");
}
});
let query = (sql, cb)=>{
connection.query(sql, (err, rows)=>{
cb(err, rows);
});
};
connection.end();
exports.query = query;
结束连接
//结束连接
connection.end(function(err){
});
//强制结束 销毁连接
connection.destroy(function(){
});
连接池
连接池有助于减少连接到MySQL服务器的时间,通过重用以前的连接可以避免查询的延迟,减少建立新连接所带来的开销。
连接池并未初始化连接所有连接,当需要操作数据库时首先需要先获取连接对象,获取连接对象可采用pool.query()
、pool.execute()
、pool.getConnection()
等的方法。pool.getConnection()
获取连接对象操作完后建议主动使用connection.release()
方法释放连接。pool.query()
和pool.execute()
自动获取连接后会释放连接。
const mysql = require("mysql");
const dbcfg = {
host:"127.0.0.1",
port:3306,
user:"root",
password:"root",
database:"pomelo"
};
//创建连接池
const pool = mysql.createPool(dbcfg);
//从连接池获取连接
let query = (sql, cb)=>{
//从连接池获取连接
pool.getConnection((err, connection)=>{
if(err){
cb(err);
return;
}
//执行SQL语句
connection.query(sql, (err, rows)=>{
//释放连接
connection.release();
//回调处理
if(err){
cb(err);
return;
}
//判断查询记录行数
let data = rows;
if(rows.length === 1){
data = rows[0];
}
cb(err, data);
});
});
};
exports.query = query;
const mysql = require("mysql2");
let config = {};
config.host = "127.0.0.1";
config.port = 3306;
config.user = "root";
config.password = "root";
config.database = "pomelo";
config.charset = "utf8mb4";
//创建连接池
const pool = mysql.createPool(config);
let db = {};
//查询
db.select = (sql, callback)=>{
pool.getConnection((error, connection)=>{
if(!error){
let query = connection.query(sql, (err, ret)=>{
if(!err){
if(ret.length===1){
ret = ret[0];
}
callback(null, ret);
}else{
callback(err, null);
}
});
query.on("error", error=>{
console.error("mysql query error: %s", error);
}).on("end", _=>{
connection.release();
});
}else{
callback(error, null);
}
});
};
module.exports = db;
//进程退出时自动关闭连接池
process.on("exit", async(code)=>{
try{
await pool.end();
}catch(e){
console.error(e);
}
});
对mysql封装
const mysql = require("mysql");
const config = {
host:"127.0.0.1",
port:3306,
user:"root",
password:"root",
database:"pomelo"
};
let db = {};
//创建连接池
const pool = mysql.createPool(config);
//执行查询
db.query = (sql, callback)=>{
pool.getConnection((error, connection)=>{
if(error){
callback(error, null);
}else{
connection.query(sql, (err, result)=>{
connection.release();//释放连接
if(err){
callback(err, null);
}else{
callback(null, result);
}
});
}
});
};
//查询操作
db.select = (sql, callback)=>{
pool.getConnection((error, connection)=>{
if(error){
callback(err, null);
}else{
connection.query(sql, (err, result)=>{
connection.release();//释放连接
//回调处理
if(err){
callback(err.message, null);
}else{
if(result.length === 1){
result = result[0];
}
callback(null, result);
}
});
}
});
};
//插入数据
db.insert = (sql, values, callback)=>{
pool.getConnection((error, connection)=>{
if(error){
callback(error, null);
}else{
connection.query(sql, values, (err, result)=>{
connection.release();
if(err){
callback(err.message, null);
}else{
callback(null, result.insertId);
}
});
}
});
};
//更新数据
db.update = (sql, values, callback)=>{
pool.getConnection((error, connection)=>{
if(error){
callback(error, null);
}else{
connection.query(sql, values, (err, result)=>{
connection.release();
if(err){
callback(err.message, null);
}else{
callback(null, result.affectedRows);
}
});
}
});
};
//删除数据
db.delete = (sql, callback)=>{
pool.getConnection((error, connection)=>{
if(error){
callback(error, null);
}else{
connection.query(sql, (err, result)=>{
connection.release();
if(err){
callback(err.message, null);
}else{
callback(null, result.affectedRows);
}
});
}
});
};
module.exports = db;
使用promise方式处理
const mysql = require("mysql2");
//数据库连接参数
let config = {};
config.host = "127.0.0.1";
config.port = 3306;
config.user = "root";
config.password = "root";
config.database = "pomelo";
config.charset = "utf8mb4";
//创建连接池
const pool = mysql.createPool(config);
let db = {};
//查询
db.select = (sql)=>{
return new Promise((resolve, reject)=>{
pool.getConnection((error, connection)=>{
if(error){
reject(error);
}else{
connection.query(sql, (err, rows)=>{
if(err){
reject(err);
}else{
if(rows.length === 1){
rows = rows[0];
}
resolve(rows);
}
connection.release();
});
}
});
});
};
module.exports = db;
//进程退出时自动关闭连接池
process.on("exit", async(code)=>{
try{
await pool.end();
}catch(e){
console.error(e);
}
});
使用
const router = require("express").Router();
const mysql = require("../util/mysql");
router.get('/index',async (req, res, next)=>{
let json = {};
json.title = "default index page";
json.message = "hello world";
const sql = "SELECT * FROM game_user";
const ret = await mysql.select(sql);
console.log(ret);
res.render("index/index.html", json);
});
module.exports = router;
使用ES7的async/await方式封装mysql
const mysql = require("mysql");
const config = {
host:"127.0.0.1",
port:3306,
user:"root",
password:"root",
database:"pomelo"
};
//创建连接池
const pool = mysql.createPool(config);
let db = {};
//执行查询
db.query = (sql, values)=>{
return new Promise((resolve, reject)=>{
pool.getConnection((error, connection)=>{
if(error){
reject(error);
}else{
connection.query(sql, values, (err, result)=>{
if(err){
reject(err);
}else{
resolve(result);
}
connection.release();//释放连接
});
}
});
});
};
db.select = (sql, values)=>{
return new Promise((resolve, reject)=>{
pool.getConnection((error, connection)=>{
if(error){
reject(error);
}else{
connection.query(sql, values, (err, rows)=>{
if(err){
reject(err);
}else{
if(rows.length===1){
rows = rows[0];
}else if(rows.length === 0){
rows = null;
}
resolve(rows);
}
connection.release();//释放连接
});
}
});
});
};
db.update = (sql, values)=>{
return new Promise((resolve, reject)=>{
pool.getConnection((error, connection)=>{
if(error){
reject(error);
}else{
connection.query(sql, values, (err, result)=>{
if(err){
reject(err);
}else{
resolve(result.affectedRows);//受影响行数
}
connection.release();//释放连接
});
}
});
});
};
db.insert = (sql, values)=>{
return new Promise((resolve, reject)=>{
pool.getConnection((error, connection)=>{
if(error){
reject(error);
}else{
connection.query(sql, values, (err, result)=>{
if(err){
reject(err);
}else{
resolve(result.insertId);//插入的主键
}
connection.release();//释放连接
});
}
});
});
};
db.delete = (sql, values)=>{
return new Promise((resolve, reject)=>{
pool.getConnection((error, connection)=>{
if(error){
reject(error);
}else{
connection.query(sql, values, (err, result)=>{
if(err){
reject(err);
}else{
resolve(result.affectedRows);//受影响行数
}
connection.release();//释放连接
});
}
});
});
};
module.exports = db;
使用
router.post("/login", async (req, res, next)=>{
let sql, result, md5;
const timestamp = utils.timestamp();
const username = req.body.username;
const password =req.body.password;
const csrctoken =req.body.csrctoken;
//必填参数判断
if(!username || !password || !csrctoken){
res.json({error:true, code:500, message:"参数缺失"});
return;
}
//令牌比对
if(csrctoken!==req.session.csrctoken){
res.json({error:true, code:500, message:"令牌失效,请刷新后重试!"});
return;
}
//MySQL:根据账户获取用户记录
sql = `SELECT * FROM game_user WHERE 1=1 AND username='${username}' LIMIT 1`;
result = await mysql.select(sql);
if(!result){
res.json({error:true, code:500, message:"账户不存在!"});
return;
}
const id = result.id;
const aid = result.aid;
const salt = result.salt;
//验证密码
md5 = crypto.createHash("md5").update(password).digest("hex");
md5 = crypto.createHash("md5").update(md5 + salt).digest("hex");
if(result.password !== md5){
res.json({error:true, code:500, message:"密码错误!"});
return;
}
//更新数据
sql = "UPDATE game_user SET ? WHERE 1=1 AND id=?";
result = await mysql.update(sql, [{last_login_time:timestamp}, id]);
if(result === 0){
res.json({error:true, code:500, message:"更新失败!"});
return;
}
}