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);
});

 

--本文結束,感謝您的閱讀。

相關文章
相關標籤/搜索