關于node操作mysql數據庫示例代碼分享

這篇文章主要介紹了node操作數據庫,結合實例形式較為詳細的分析了node操作數據庫的連接、增刪改查、事務處理及錯誤處理相關操作技巧,需要的朋友可以參考下

本文實例講述了node操作mysql數據庫的方法。分享給大家供大家參考,具體如下:

1、建立數據庫連接:createConnection()方法

該方法接受一個對象作為參數,該對象有四個常用的屬性host,user,password,database。與php中鏈接數據庫的參數相同。屬性列表如下:

host 連接數據庫所在的主機名. (默認: localhost)
port 連接端口. (默認: 3306)
localAddress 用于TCP連接的IP地址. (可選)
socketPath 鏈接到unix域的路徑。在使用host和port時該參數會被忽略.
user MySQL用戶的用戶名.
password MySQL用戶的密碼.
database 鏈接到的數據庫名稱 (可選).
charset 連接的字符集. (默認: ‘UTF8_GENERAL_CI’.設置該值要使用大寫!)
timezone 儲存本地時間的時區. (默認: ‘local’)
stringifyObjects 是否序列化對象. See issue #501. (默認: ‘false’)
insecureAuth 是否允許舊的身份驗證方法連接到數據庫實例. (默認: false)
typeCast 確定是否講column值轉換為本地Javascript類型列值. (默認: true)
queryFormat 自定義的查詢語句格式化函數.
supportBigNumbers 數據庫處理大數字(長整型和含小數),時應該啟用 (默認: false).
bigNumberStrings 啟用 supportBigNumbers和bigNumberStrings 并強制這些數字以字符串的方式返回(默認: false).
dateStrings 強制日期類型(TIMESTAMP, DATETIME, DATE)以字符串返回,而不是一javascript Date對象返回. (默認: false)
debug 是否開啟調試. (默認: false)
multipleStatements 是否允許在一個query中傳遞多個查詢語句. (Default: false)
flags 鏈接標志.

還可以使用數據庫例如:

var?connection?=?mysql.createConnection('mysql://user:pass@host/db?debug=true&charset=BIG5_CHINESE_CI&timezone=-0700');

2、結束數據庫連接end()和destroy()

end()接受一個,并且會在query結束之后才觸發,如果query出錯,仍然會終止鏈接,錯誤會傳遞到回調函數中處理。

destroy()立即終止數據庫連接,即使還有query沒有完成,之后的回調函數也不會在觸發。

3、創建連接池 createPool(Object)? Object和createConnection參數相同。

可以監聽connection,并設置

pool.on('connection',?function(connection)?{  ?connection.query('SET?SESSION?auto_increment_increment=1')  });

connection.release()釋放鏈接到連接池。如果需要關閉連接并且刪除,需要使用connection.destroy()

pool除了接受和connection相同的參數外,還接受幾個擴展的參數

createConnection 用于創建鏈接的函數. (Default: mysql.createConnection)
waitForConnections 決定當沒有連接池或者鏈接數打到最大值時pool的行為. 為true時鏈接會被放入隊列中在可用是調用,為false時會立即返回error. (Default: true)
connectionLimit 最大連接數. (Default: 10)
queueLimit 連接池中連接請求的烈的最大長度,超過這個長度就會報錯,值為0時沒有限制. (Default: 0)

4、連接池集群

允許不同的host鏈接

//?create  var?poolCluster?=?mysql.createPoolCluster();  poolCluster.add(config);?//?anonymous?group  poolCluster.add('MASTER',?masterConfig);  poolCluster.add('SLAVE1',?slave1Config);  poolCluster.add('SLAVE2',?slave2Config);  //?Target?Group?:?ALL(anonymous,?MASTER,?SLAVE1-2),?Selector?:?round-robin(default)  poolCluster.getConnection(function?(err,?connection)?{});  //?Target?Group?:?MASTER,?Selector?:?round-robin  poolCluster.getConnection('MASTER',?function?(err,?connection)?{});  //?Target?Group?:?SLAVE1-2,?Selector?:?order  //?If?can't?connect?to?SLAVE1,?return?SLAVE2.?(remove?SLAVE1?in?the?cluster)  poolCluster.on('remove',?function?(nodeId)?{  ???console.log('REMOVED?NODE?:?'?+?nodeId);?//?nodeId?=?SLAVE1  });  poolCluster.getConnection('SLAVE*',?'ORDER',?function?(err,?connection)?{});  //?of?namespace?:?of(pattern,?selector)  poolCluster.of('*').getConnection(function?(err,?connection)?{});  var?pool?=?poolCluster.of('SLAVE*',?'RANDOM');  pool.getConnection(function?(err,?connection)?{});  pool.getConnection(function?(err,?connection)?{});  //?destroy  poolCluster.end();

鏈接集群的可選參數

canRetry 值為true時,允許連接失敗時重試(Default: true)
removeNodeErrorCount 當連接失敗時 errorCount 值會增加. 當errorCount 值大于 removeNodeErrorCount 將會從PoolCluster中刪除一個節點. (Default: 5)
defaultSelector 默認選擇器. (Default: RR)
RR 循環. (Round-Robin)
RANDOM 通過隨機函數選擇節點.
ORDER 無條件地選擇第一個可用節點.

5、切換用戶/改變連接狀態

Mysql允許在比斷開連接的的情況下切換用戶

connection.changeUser({user?:?'john'},?function(err)?{  ?if?(err)?throw?err;  });

參數

user 新的用戶 (默認為早前的一個).
password 新用戶的新密碼 (默認為早前的一個).
charset 新字符集 (默認為早前的一個).
database 新數據庫名稱 (默認為早前的一個).

6、處理服務器連接斷開

var?db_config?=?{  ??host:?'localhost',  ??user:?'root',  ??password:?'',  ??database:?'example'  };  var?connection;  function?handleDisconnect()?{  ?connection?=?mysql.createConnection(db_config);?//?Recreate?the?connection,?since  ?????????????????????????//?the?old?one?cannot?be?reused.  ?connection.connect(function(err)?{???????//?The?server?is?either?down  ??if(err)?{???????????????????//?or?restarting?(takes?a?while?sometimes).  ???console.log('error?when?connecting?to?db:',?err);  ???setTimeout(handleDisconnect,?2000);?//?We?introduce?a?delay?before?attempting?to?reconnect,  ??}???????????????????//?to?avoid?a?hot?loop,?and?to?allow?our?node?script?to  ?});???????????????????//?process?asynchronous?requests?in?the?meantime.  ?????????????????????//?If?you're?also?serving?http,?display?a?503?error.  ?connection.on('error',?function(err)?{  ??console.log('db?error',?err);  ??if(err.code?===?'PROTOCOL_CONNECTION_LOST')?{?//?Connection?to?the?MySQL?server?is?usually  ???handleDisconnect();?????????????//?lost?due?to?either?server?restart,?or?a  ??}?else?{???????????????????//?connnection?idle?timeout?(the?wait_timeout  ???throw?err;?????????????????//?server?variable?configures?this)  ??}  ?});  }  handleDisconnect();

7、轉義查詢值

為了避免SQL注入攻擊,需要轉義用戶提交的數據。可以使用connection.escape() 或者 pool.escape()

例如:

var?userId?=?'some?user?provided?value';  var?sql??=?'SELECT?*?FROM?users?WHERE?id?=?'?+?connection.escape(userId);  connection.query(sql,?function(err,?results)?{  ???//?...  });

或者使用?作為占位符

connection.query('SELECT?*?FROM?users?WHERE?id?=??',?[userId],?function(err,?results)?{  ???//?...  });

不同類型值的轉換結果

Numbers 不變
Booleans 轉換為字符串 ‘true’ / ‘false’
Date 對象轉換為字符串 ‘YYYY-mm-dd HH:ii:ss’
Buffers 轉換為是6進制字符串
Strings 不變
Arrays => [‘a’, ‘b’] 轉換為 ‘a’, ‘b’
嵌套數組 [[‘a’, ‘b’], [‘c’, ‘d’]] 轉換為 (‘a’, ‘b’), (‘c’, ‘d’)
Objects 轉換為 key = ‘val’ pairs. 嵌套對象轉換為字符串.
undefined / null ===> NULL
NaN / Infinity 不變. MySQL 不支持這些值,? 除非有工具支持,否則插入這些值會引起錯誤.

轉換實例:

var?post?=?{id:?1,?title:?'Hello?MySQL'};  var?query?=?connection.query('INSERT?INTO?posts?SET??',?post,?function(err,?result)?{  ???//?Neat!  });  console.log(query.sql);?//?INSERT?INTO?posts?SET?`id`?=?1,?`title`?=?'Hello?MySQL'

或者手動轉換

var?query?=?"SELECT?*?FROM?posts?WHERE?title="?+?mysql.escape("Hello?MySQL");  console.log(query);?//?SELECT?*?FROM?posts?WHERE?title='Hello?MySQL'

8、轉換查詢標識符

如果不能信任SQL標識符(數據庫名、表名、列名),可以使用轉換方法mysql.escapeId(identifier);

var?sorter?=?'date';  var?query?=?'SELECT?*?FROM?posts?ORDER?BY?'?+?mysql.escapeId(sorter);  console.log(query);?//?SELECT?*?FROM?posts?ORDER?BY?`date`

支持轉義多個

var?sorter?=?'date';  var?query?=?'SELECT?*?FROM?posts?ORDER?BY?'?+?mysql.escapeId('posts.'?+?sorter);  console.log(query);?//?SELECT?*?FROM?posts?ORDER?BY?`posts`.`date`

可以使用??作為標識符的占位符

var?userId?=?1;  var?columns?=?['username',?'email'];  var?query?=?connection.query('SELECT????FROM????WHERE?id?=??',?[columns,?'users',?userId],?function(err,?results)?{  ???//?...  });  console.log(query.sql);?//?SELECT?`username`,?`email`?FROM?`users`?WHERE?id?=?1

9、準備查詢

可以使用mysql.format來準備查詢語句,該函數會自動的選擇合適的方法轉義參數。

var?sql?=?"SELECT?*?FROM????WHERE????=??";  var?inserts?=?['users',?'id',?userId];  sql?=?mysql.format(sql,?inserts);

10、自定義格式化函數

connection.config.queryFormat?=?function?(query,?values)?{  ???if?(!values)?return?query;  ???return?query.replace(/:(w+)/g,?function?(txt,?key)?{  ????if?(values.hasOwnProperty(key))?{  ?????return?this.escape(values[key]);  ????}  ????return?txt;  ???}.bind(this));  };  connection.query("UPDATE?posts?SET?title?=?:title",?{?title:?"Hello?MySQL"?});

11、獲取插入行的id

當使用自增主鍵時獲取插入行id,如:

connection.query('INSERT?INTO?posts?SET??',?{title:?'test'},?function(err,?result)?{  ???if?(err)?throw?err;  ???console.log(result.insertId);  ??});

12、流處理

有時你希望選擇大量的行并且希望在數據到達時就處理他們,你就可以使用這個方法

var?query?=?connection.query('SELECT?*?FROM?posts');  ??query  ???.on('error',?function(err)?{  ????//?Handle?error,?an?'end'?event?will?be?emitted?after?this?as?well  ???})  ???.on('fields',?function(fields)?{  ????//?the?field?packets?for?the?rows?to?follow  ???})  ???.on('result',?function(row)?{  ????//?Pausing?the?connnection?is?useful?if?your?processing?involves?I/O  ????connection.pause();  ????processRow(row,?function()?{  ?????connection.resume();  ????});  ???})  ???.on('end',?function()?{  ????//?all?rows?have?been?received  ???});

13、混合查詢語句(多語句查詢)

因為混合查詢容易被SQL注入攻擊,默認是不允許的,可以使用:

var?connection?=?mysql.createConnection({multipleStatements:?true});

開啟該功能。

混合查詢實例:

connection.query('SELECT?1;?SELECT?2',?function(err,?results)?{  ???if?(err)?throw?err;  ???//?`results`?is?an?array?with?one?element?for?every?statement?in?the?query:  ???console.log(results[0]);?//?[{1:?1}]  ???console.log(results[1]);?//?[{2:?2}]  ??});

同樣可以使用流處理混合查詢結果:

var?query?=?connection.query('SELECT?1;?SELECT?2');  ??query  ???.on('fields',?function(fields,?index)?{  ????//?the?fields?for?the?result?rows?that?follow  ???})  ???.on('result',?function(row,?index)?{  ????//?index?refers?to?the?statement?this?result?belongs?to?(starts?at?0)  ???});

如果其中一個查詢語句出錯,Error對象會包含err.index指示錯誤語句的id,整個查詢也會終止。

混合查詢結果的流處理方式是做實驗性的,不穩定。

14、事務處理

connection級別的簡單事務處理

connection.beginTransaction(function(err)?{  ???if?(err)?{?throw?err;?}  ???connection.query('INSERT?INTO?posts?SET?title=?',?title,?function(err,?result)?{  ????if?(err)?{  ?????connection.rollback(function()?{  ??????throw?err;  ?????});  ????}  ????var?log?=?'Post?'?+?result.insertId?+?'?added';  ????connection.query('INSERT?INTO?log?SET?data=?',?log,?function(err,?result)?{  ?????if?(err)?{  ??????connection.rollback(function()?{  ???????throw?err;  ??????});  ?????}  ?????connection.commit(function(err)?{  ??????if?(err)?{  ???????connection.rollback(function()?{  ????????throw?err;  ???????});  ??????}  ??????console.log('success!');  ?????});  ????});  ???});  ??});

15、錯誤處理

err.code?=?string  err.fatal?=>?boolean

? 版權聲明
THE END
喜歡就支持一下吧
點贊6 分享