Node.js MySQL

安装MySQL驱动

# 全局安装mysql
$ npm i -g mysql

node-mysql2node-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;
     }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容