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); });
--本文結束,感謝您的閱讀。