Node.js 的第三方模块的使用基本上是两个步骤:javascript
第一步:安装三方模块: npm install 模块名 或者 cnpm install 模块名;java
第二步:加载模块。node
其实,Node.js 对 NoSql (Not only sql 不只仅是SQL,非关系型数据库)数据库支持度比较好。非关系型数据库集成JS的执行环境,BOSN数据类型进行存放。典型的非关系型数据库是MongoDB等。然而我没有接触过非关系型数据库,这里就使用MySQL了。mysql
第一步:建立数据库的链接并创建链接es6
第二步:执行 sql 语句sql
第三步:处理结果集数据库
第四步:关闭数据库链接npm
const conn = mysql.createConnection( opt )数组
opt 是数据库链接信息的配置,promise
let opt = { host:"127.0.0.1", port:"3306", user:"root", password:"", database:"数据库名" };
conn.query(sql [,params] , callback(error , result , fields) )
let sql = “select * from 表名”;
回调函数callback有三个参数:
error:执行错误信息,执行成功返回null;
result: 返回执行sql语句的结果。受影响的行数和执行时间,以及执行查询操做的查询结果。
fields: 表的结构和字段类型
query( ) 方法会自动执行创建链接的方法
conn.query(sql ,(error , result , fields )=>{ ...... });
conn.query(sql ,(error , result , fields )=>{ 处理结果集 });
方法一:conn.end( )
延迟等待关闭:接受到关闭信号以后,不当即结束和数据库的链接,等待全部的sql执行完成后再释放资源。
方法二:conn.destroy( )
当即关闭:接收到关闭信号后,当即释放资源,不关心是否存在还没有完成的sql。
一般咱们使用 conn.end( ) 关闭链接,须要重启或者关闭服务器时使用conn.destroy( )。
代码事例
// 第三方模块使用 // 下载第三方模块 // 加载三方模块 const mysql = require("mysql"); // 访问数据库操做 // 1. 建立数据库 // 1.1 配置数据库信息 let opt = { host: "127.0.0.1", port:"3306", user:"root", password:"", database:"数据库名" }; // 1.2 建立数据库链接对象 const conn = mysql.createConnection(opt); // 1.3 链接数据库,用于测试链接 // conn.connect((error)=>{ // console.log(error); // }) // 2 执行 sql 语句 // 2.1 sql 语句 let sql =" select * from t_user"; // 2.2 执行sql语句,query()方法中自带创建链接方法,因此不须要再链接数据库 conn.query(sql,(error,result,fields)=>{ // 3 处理结果集 // 简单的打印出结果 console.log(error); console.log(result); }); // 4 关闭数据库链接 conn.end();
mysql.createConnection(opt)中的opt是数据库的链接参数,具体配置信息以下:
// opt 的配置项 const mysql = require("mysql"); let opt = { host:"127.0.0.1", port:"3306", user:"root", password:"", database:"数据库名" // 参数项不少,注意经常使用选项 // 参数的解释 /* host: 数据库链接地址 (Default: localhost) HTTP 协议链接 port: 数据了链接端口 (Default: 3306) user: 数据库链接用户名 password: 数据库链接密码 database: 默认链接库的指定 charset: 链接数据的默认字符集 (Default: 'UTF8_GENERAL_CI') sql :set names utf8; timezone: 设置数据的仿佛闻时区,当前程序运行的本地时区 +HH:MM or -HH:MM. (Default: 'local') localAddress: 集群服务器数据库链接 (TCP/IP) socketPath: 套接字通讯地址 广域网IP链接方式 (链接UNIX通讯链接地址) connectTimeout: 链接超时时间 (Default: 10000ms) stringifyObjects: 是否将对象强制装换为字符串格式 (date time datetime year ) (Default: false) dateStrings: 是否开启时间和字符串的自动转换,(Default: false) typeCast: 是否开启数据的格式转换 (int,float……)=>number varchar=>string date=>Date …… (Default: true) bigNumberStrings: 高精度数值存储转换 将超过js Number 能够存放的数值转换为字符串进行转换,以保持精度 debug: 是否开启调试模式 (Default: false) insecureAuth: 是否可使用旧链接信息进行认证登陆(Default: false) queryFormat: 查询语句占位符定义(查询占位符) supportBigNumbers: 是否能够直接使用数据库大数据存储模式 (Default: false). trace: 是否能够消息跟踪模式 (Default: true) multipleStatements: 是否能够在一个query方法中执行 多条 sql (Default: false) flags: 数据库的链接标识符 ssl: 加密链接信息 */ };
在conn.query(sql [,params] , callback(error , result , fields) )方法中有个参数 params,用来携带sql语句中的占位符(?或者 ??)所表明的变量。
如:let sql = "select * from t_user where userTel = ? ";
let params = 电话号码;
conn.query(sql , params ,callback(error , result ,fields) )。
这样在执行sql语句时,等价于 let sql = "select * from t_user where userTel = 电话号码 "。
params 参数的 sql 拼接方式取决于 params 的数据类型,常见的是 Number、String、Boolean、Array、Object物种使用方法。具体字母使用,见下:
/* Numbers 不作任何操做直接替换一个 ? let no = 1; select * from table where id = ? select * from table where id = 1 Strings 将值 包裹在 ' ' 之间进行 一个 ? 替换 let name = "tom"; select * from table where name = ? select * from table where name = 'tom' Booleans 会被替换成 true/false 替换一个 ? 数据库会将 true 替换为 1 false 替换为 0 Date 被转化为 'YYYY-mm-dd HH:ii:ss' 字符串 数据库会根据类型自动识别 Buffers 将缓存对象转换为 HEX 编码 替换一个 ? 会在 十六进制前 增长 X ==> 数据库会根据类型自动转换 undefined 或 null 转换为 NULL NaN 和 Infinity 不转换直接报错 NaN (值) ==> 意思叫作不是数值 类型 Number Infinity (值) ==> 意思是无穷 类型 Number Arrays 一维数组会被转换为 固定格式 '值' '值' '值' …… 值得个数替换多个 ? 其中 '' 取决于元素值得类型 let arr = ["a",2,new Date(),true]; let sql = insert into table (c1,c2,c3,c4) values (?,?,?,?); insert into table (c1,c2,c3,c4) values ('a',2,'YYYY-MM-DD HH:ii:ss',true); 多维数组 (二维) ['值','值','值'…… ] ['值','值','值'…… ] 以一维数组的元素个数为基准替换对应的 ?个数 let arr = [[1,2,3],[4,5,6]]; 1,2,3 ==> ? 4,5,6 ==> ? in(v,v,v) not in(v,v,v) Objects {key:value} ==> 存放具备关联性的数据 ==> {name:"aaa",nikeName:"bbbb",loginName:"ccc",pwd:"dddd"} 转换规则 {key1:value1,key2:value2} ==> 一个总体 key1=value1,key2=value2 ==> 用于替换一个 ? update table set cName=value,cName=value,…… let user = {nikeName:"tom",userTel:"123456",password:"123",userImgUrl:"ssss.png"} --- insert into table (……) values (?,?,?,?); insert into table set 列名=值,列名=值,…… ==> insert into table set ? ArraysAndObjects [{},{}] {} => 替换一个 ? ==> key1=value1,key2=value2 {} => 替换一个 ? ==> key1=value1,key2=value2 ObjectsAndArrays {key1=[a,b],key2=[c,d]} key1=[a,b],key2=[c,d] ==> 替换一个 ? 例如 select * from t_user where id in( ? ) and userTel = ?; let params = [[],String] update t_user set ? where id = ?; let params = [{},number] …… */
在用 “?” 替换时,会多出 ‘ ’,可是在 sql 语句中列名和表名没有单引号,若用 “?” 替换时,会报错。此时就会用到 ‘??’。
百度百科:链接池基本的思想是在系统初始化的时候,将数据库链接做为对象存储在内存中,当用户须要访问数据库时,并不是创建一个新的链接,而是从链接池中取出一个已创建的空闲链接对象。使用完毕后,用户也并不是将链接关闭,而是将链接放回链接池中,以供下一个请求访问使用。而链接的创建、断开都由链接池自身来管理。同时,还能够经过设置链接池的参数来控制链接池中的初始链接数、链接的上下限数以及每一个链接的最大使用次数、最大空闲时间等等。也能够经过其自身的管理机制来监视数据库链接的数量、使用状况等。
我的理解:在服务器启动的时候,创建多个数据库链接放入链接池。每当用户访问数据库时,直接从链接池中取出一个已创建的空闲链接对象,对数据库进行操做。使用完成后,该链接转为空闲状态,等待用户再次使用(不会关闭链接)。若用户访问数据库时链接池中没有空闲链接,则该用户进入等待队列等待空闲的链接对象(队列先进先出原则,栈先进后出原则)。
第一步:建立链接池。先配置数据库链接参数设置,而后再建立链接池:const pool = mysql.createPool(opt);
第二步:获取链接池中空闲对象: pool.getConnection((error,conn)=>{...});
第三步:执行 sql 语句:conn.query(sql ,callback);
第四步:处理结果集
第五步:释放当前链接:pool.releaseConnection(conn);
具体使用到代码以下:
const mysql = require("mysql"); // 1. 建立链接池 // 1.1 数据库链接参数设置 let opt = { // 数据库链接池参数 包含 数据库建立方法createConnection中的全部参数 host: "127.0.0.1", port: "3306", user: "root", password: "", database:"tournote" // 链接池特有参数,包括 初始化时空闲的链接对象个数、队列等待方式、链接池超时时间等 // acquireTimeout: 获取链接时的 超时时间 (Default: 10000ms) // waitForConnections: 用户请求链接时,若是没有空闲链接或者链接上限处理方式 (Default: true) // true:用户继续等待 // false:直接拒绝用户请求 // connectionLimit: 在链接建立时 该属性只被执行一次:初始化链接池空闲链接数量. (Default: 10) // queueLimit: 队列容许 最大的等待用户数 (Default: 0) // 0 ==> 无上限值 } // 1.2 建立链接池 const pool = mysql.createPool(opt); // 2. 获取链接池中空闲对象 // pool.getConnection(callback(error,conn)); // error 表示获取对象是否成功,成功时返回 null // conn 成功后返回的链接对象 pool.getConnection((error,conn)=>{ if(error){//得到到空闲链接对象时,返回null,因此error不为null时表示未得到空闲链接对象 console.log("获取链接池中空闲链接失败"+error.message); return; } // 3. 执行 sql 语句 let sql = "select * from t_user"; conn.query(sql,(error,result,fields)=>{ // 4. 处理结果集 if(error){ console.log("执行失败"); return; } console.log(result); }); // 5. 释放当前链接 pool.releaseConnection(conn); });
封装数据库链接工具模块(相似于java语言对工具类),能够简化在项目对于同一个数据库进行操做时 重复定义代码。
做用:不须要重复建立、配置参数和重复获取数据库链接,将结果交给用户本身处理。
具体封装的工具模块以下:其中用到了链接池技术和es6 中 promise。
注意:下属代码中,exec = function (sql ,params) {....}应该改成exec = function (sql="select 1",params=[]) {....}。这里之因此写错,是为了代码显示颜色,可读性好。这里应该是编译器到漏洞。若我正确写,下述代码将变成全白一片。
// 获取 node.js 的第三方模块 mysql const mysql = require("mysql"); // 数据库链接参数设置 let opt = { host:"127.0.0.1", port:"3306", user:"root", password:"", database:"数据库名" } // 建立链接池 const pool = mysql.createPool(opt); // 定义执行函数 //这里注意了,注意!注意!这里参数sql和params应该有默认值,可是开源中国博客这里的编译器有点问题,加上参数代码代码高亮显示就没了,阅读性太差 const exec = function(sql,params){//这里参数sql和params应该有默认值,像这样sql="select 1",params=[] return new Promise((resolve,reject)=>{ // 执行sql 获取结果 pool.query(sql,params,(error,result,fields)=>{ if(error){ reject(error); return; } let obj = { "result":result, "fields":fields } // Node.js 中 Promise 的resolve 方法只能接受一个参数 resolve(obj); // resolve({result,fields}) }); }); } module.exports = { exec }
本工具类的使用:
// 一、加载工具模块 const { exec } = require("./dbUtil"); // 二、编写sql let sql1 = "select * from t_user where nikeName = ? "; let sql2 = "select * from t_tour where userId = ? "; let nikeName = ["haha"]; // 三、执行sql(调用exec()方法), promise的方法,成功执行.then()方法,失败执行.catch()方法 exec(sql1,nikeName).then(({result,fields})=>{ console.log(result[0].id); return exec(sql2,result[0].id); }).then(({result,fields})=>{ console.log(result); }).catch((error)=>{ console.log(error.message); });
--本文结束,感谢您的阅读。