Node.js---0五、node.js的三方模块之MySQL

1、第三方模块的使用和数据库访问的通用步骤

    一、第三方模块的使用步骤

    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

2、第三方模块 MySQL 模块

    一、简单的使用

        1.1 建立数据库的链接对象 : createConnection( )

        const conn = mysql.createConnection( opt )数组

        opt 是数据库链接信息的配置,promise

        let opt = { host:"127.0.0.1", port:"3306", user:"root", password:"", database:"数据库名" };

        1.2 执行 sql 语句 : query( )

        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 )=>{ ...... });

        1.3 处理结果集

        conn.query(sql ,(error , result , fields )=>{ 处理结果集 });

        1.4 关闭链接

        方法一: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物种使用方法。具体字母使用,见下:

        3.1 占位符 ‘?’:值替换符

/*
    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]

        ……
    
 */

        3.2 占位符 ‘??’:列替换符

        在用 “?” 替换时,会多出 ‘ ’,可是在 sql 语句中列名表名没有单引号,若用 “?” 替换时,会报错。此时就会用到 ‘??’。

    四、数据库链接池

        4.1 链接池介绍

        百度百科:链接池基本的思想是在系统初始化的时候,将数据库链接做为对象存储在内存中,当用户须要访问数据库时,并不是创建一个新的链接,而是从链接池中取出一个已创建的空闲链接对象。使用完毕后,用户也并不是将链接关闭,而是将链接放回链接池中,以供下一个请求访问使用。而链接的创建、断开都由链接池自身来管理。同时,还能够经过设置链接池的参数来控制链接池中的初始链接数、链接的上下限数以及每一个链接的最大使用次数、最大空闲时间等等。也能够经过其自身的管理机制来监视数据库链接的数量、使用状况等。

        我的理解:在服务器启动的时候,创建多个数据库链接放入链接池。每当用户访问数据库时,直接从链接池中取出一个已创建的空闲链接对象,对数据库进行操做。使用完成后,该链接转为空闲状态,等待用户再次使用(不会关闭链接)。若用户访问数据库时链接池中没有空闲链接,则该用户进入等待队列等待空闲的链接对象(队列先进先出原则,栈先进后出原则)。

        4.2 链接池的使用方法

        第一步:建立链接池。先配置数据库链接参数设置,而后再建立链接池: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);
});

 

--本文结束,感谢您的阅读。

相关文章
相关标签/搜索