NodeJs——使用tedious連接 sql server

項目地址:tedious

安裝

npm i --save tedious

配置 config.js

基礎(chǔ)的配置信息包括
server -- 數(shù)據(jù)庫所在服務(wù)器,
userName -- 用戶名,
password -- 密碼,
options { database:' '} 數(shù)據(jù)庫名等配置信息,詳細(xì)的配置在 官方API 可以看到

let Connection= require('tedious').Connection
let Request = require('tedious').Request
let connectionCfg = {
    server: '127.0.0.1',  
    userName: 'yourname',
    password: 'yourpassword',
    options: { database: 'database' }  
  }
let connection = new Connection('connectionCfg')
connection.on('connect', function (err){
    if (!err) {
      executeStatement(querySql)
    }
})

function executeStatement ( querySql) { 
    let request = new Request(querySql , (err, rowCount)=>{
      if (err) {
        console.error(err)
        return; //創(chuàng)建 request 實例失敗
      }
    })
    var result = [];  
    request.on('row', function(columns,idx) {
      var obj = {}  
      columns.forEach( function(column) {
        if(column.value !== null){
         var key = column.metadata.colName
         var val = column.value
          obj[key] = val
        }
      });
    result.push(obj)
    })

    request.on('done', function ( rowCount, more, rows) {
      return result
    })
}

代碼寫到這里感覺還是一片順利,實際上已經(jīng)有一兩個小坑需要提醒一下了。

  1. requestrow 事件,回調(diào)函數(shù)中的參數(shù) columns 受 config.options.useColumnNames 影響,默認(rèn)為false,設(shè)置為true或者其他任何類型轉(zhuǎn)換會判斷為true的值時,返回的結(jié)果為object類型,這里的設(shè)置決定了遍歷方法。詳細(xì)的config配置說明在 這里
  2. requestdone事件,官方的說法是:創(chuàng)建Request實例時使用普通的sql查詢時,查詢完畢會觸發(fā)該事件,請求類型為存儲過程的話,觸發(fā) doneInProcdoneProc事件,實際在在使用過程中,即使將普通 sql 查詢語句拼接成字符串傳入 Request實例中也不會觸發(fā)done事件,建議還是使用doneProc事件。語法如下:
    request.on('doneProc', function (rowCount, more, returnStatus, rows) { });
    判斷callback中的more == false時,視為請求完成。

常見問題

報錯
RequestError:requests can only be made in the LoggedIn state, not the SentClientRequest state
在我將配置項用作 module 引入時,經(jīng)常碰到這個問題: 進(jìn)入頁面->觸發(fā)數(shù)據(jù)庫操作->返回上一頁->再返回該頁時,就得到一個 Internal Server Error的500頁面。
翻 issue 時發(fā)現(xiàn)主要是因為一個問題 , 套用作者原話:issue地址

only one request can be performed on a connection at a time.

在同一時間同一個連接只能執(zhí)行一個請求
具體到我的代碼中,和提出 issue 這位用戶很相似。同樣是向外暴露了一個execute引用一個該用戶核心代碼和作者的解答

controller.execute = function(session, admin, sqlCommand) {
    var MSSqlConnection = require('./MSSqlConnection');

    MSSqlConnection.on('connected', function(connection){
            _performQuery(connection, sqlCommand.toString());
    });
    ...
}

作者的解釋

Your MSSqlConnection variable is a singleton, because require caches modules. So when this code is called for the second page request, a second listener is added for the MSSqlConnection's connected event. When the connected event is emitted from MSSqlConnection, both listeners are called. This results in two calls to the Tedious Connection object's execSql function. The second call occurs before the first request has completed, and the state machine in Connection detects and reports the problem.

大概的意思就是,第二次進(jìn)入頁面時,向 connected事件加了一個監(jiān)聽器,connected事件觸發(fā)時,兩個監(jiān)聽器都被調(diào)用,第二個請求發(fā)起時,第一個請求還沒有結(jié)束(還處于 sentClientRequest的state 中),所以就報錯了。

the Request's callback signifies the completion of the request, and that another request may not be made until it is called.

創(chuàng)建 Request實例的意味著該請求完成,在這之前,其他請求不會被調(diào)用。
你很難去確定前面的請求是否已經(jīng)是完成狀態(tài),是否可以執(zhí)行下一個request,之前我不做模塊化的時候,將所有請求方法和connect全部放到一個對象中,沒有出現(xiàn)過這個問題,代碼結(jié)構(gòu)類似這樣

let nodeSql = {
  connect: function () {
    len connection = new Connection(config)
    connection.on('connect' , funciton(){
      nodeSql.connection = connection
      ....
    })
    connection.on('end', function(){
    nodeSql.connection = null
    })
    connection.on('end', function(){
    nodeSql.connection = null
    })
  },
  execute: function (querySql) {
    if(this.connection) {
     return nodeSql.executeStatement(querySql)
    }else{
      return Promise.resolve(this.connect())
      .then(()=>nodeSql.executeStatement(querySql))
    }
   }
}

這樣的代碼當(dāng)時沒遇到問題,所以我有點懵逼,只能認(rèn)定是 module的問題,為了代碼結(jié)構(gòu)清晰又不能放棄 module。好在作者還提供了連接池的使用方式,使用也非常簡單。 tedious-connection-pool

問題解決,撒花!(寫字太累了草草收尾就這樣吧)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容