NoSQL 數(shù)據(jù)庫最近一段時間都是很受追捧的,也許已經(jīng)是 Node.js 應(yīng)用程序的首選后端了。不過,你不應(yīng)該只是根據(jù)潮流來選擇拿什么技術(shù)構(gòu)建下一個項目,使用什么數(shù)據(jù)庫類型要取決于項目的特定需求。如果你的項目涉及到動態(tài)表的創(chuàng)建,實時的插入等等,那么 NoSQL 就是不錯的技術(shù)路線,而另一方面,如果項目中要處理復(fù)雜的查詢和事務(wù),那么 SQL 數(shù)據(jù)庫就更加合適了。 在本教程中,我們會向你介紹如何使用 MySQL 模塊 - 這是一個用 JavaScript 編寫的運行在 Node.js 之上的 MySQL 驅(qū)動程序。我會向你解釋如何使用該模塊連接到 MySQL 數(shù)據(jù)庫,執(zhí)行常規(guī)的 CRUD 操作,之后就是對存儲的過程進(jìn)行檢查,以及對用戶的輸入進(jìn)行轉(zhuǎn)義這些技術(shù)。
快速入門:如何在Node 中使用MySQL 也許你來這是就是為了找到一個快速的法門。如果你是想用盡可能少的時間在 Node 中啟動并運行 MySQL,我們能滿足你的需求! 以下5個簡單步驟告訴你如何在 Node 中使用 MySQL:
安裝 mysql 模塊 現(xiàn)在讓我們細(xì)化到第一步。首先,我們使用命令行創(chuàng)建一個新目錄進(jìn)進(jìn)入這個目錄。然后我們使用 npm init -y 命令創(chuàng)建 package.json 文件。-y 參數(shù)表示 npm 會使用默認(rèn)值而不會問你各種問題。 這一步假設(shè)你已經(jīng)在系統(tǒng)上安裝了 Node 和 npm。如果還沒安裝,請閱讀 SitePoint 上的這篇文章,它會指導(dǎo)你:使用 nvm 安裝 Node.js 的多個版本。 然后,我們從 npm 安裝 mysql 模塊并將其保存為項目的依賴項。項目的 dependencies (相對于 dev-dependencies) 是運行程序所需要的包。你可以閱讀了解兩者的區(qū)別。 如果你深入學(xué)習(xí)使用 npm,可以閱讀這個指南,或者在我們的論壇上提問。 入門 在我們連接到數(shù)據(jù)庫之前,有一件重要的事情就是要在你的機(jī)器上安裝和配置 MySQL。如果這件事情還沒做完,那就看看軟件主頁上的安裝說明自己去裝一個吧。 接下來我們需要做的就是創(chuàng)建一個數(shù)據(jù)庫和一個數(shù)據(jù)庫表。你可以使用一個圖形用戶界面來做到這一點,比如說 phpMyAdmin,或者就使用命令行。 對于我們這篇文章,使用的是一個名為 sitepoint 的數(shù)據(jù)庫和一個名為 employees 的表。如果你希望跟著一起操作的話,這里有一個數(shù)據(jù)庫的轉(zhuǎn)儲文件,方便你可以快速地啟動并運行起來: ![]() 連接到數(shù)據(jù)庫 ![]() 現(xiàn)在,我們在 mysql-test 目錄下創(chuàng)建一個名為 app.js 的文件,來看看如何從 Node.js 連接到 MySQL。 現(xiàn)在打開一個終端并輸入 node app.js。在連接成功建立之后,你應(yīng)該能夠在控制臺中看到“Connection established”(連接已經(jīng)建立好了)這條消息了。 如果出現(xiàn)了什么問題(例如輸入了錯誤的密碼),程序就會觸發(fā)一個回調(diào),該事件會傳遞出一個 JavaScript Error 對象(err)的實例。 你可以嘗試將其打印到控制臺以查看其中包含的有用信息以調(diào)試程序。 使用 Grunt 來監(jiān)視文件的更改 每當(dāng)我們對代碼進(jìn)行更改時,手動運行 node app.js 命令會變得有點乏味,所以讓我們來把這個操作自動化吧。 這一節(jié)并不需要跟本教程的其余部分并沒有依賴關(guān)系,不過如果照著做的話肯定會為你節(jié)省一些麻煩事兒。 我們首先得安裝幾個包: Grunt 是有名的 JavaScript 任務(wù)執(zhí)行程序,每當(dāng)監(jiān)聽到有文件發(fā)生修改時,grunt-contrib-watch 都會運行已經(jīng)預(yù)定義好的任務(wù),并且會使用 grunt-execute 來運行 node app.js 命令。 安裝完成之后,在項目根中創(chuàng)建一個名為Gruntfile.js的文件,然后在里面添加上如下代碼。 現(xiàn)在運行 grunt watch 然后修改一下 app.js 文件。Grunt 就應(yīng)該會檢測到我們修改了文件并重新運行 node app.js 命令。 ![]() 執(zhí)行查詢 ![]() 讀取 現(xiàn)在你知道如何在 Node.js 中建立 MySQL 連接了,再來看看如何執(zhí)行 SQL 查詢。我們從這里開始:建立使用 createConnection 命令連接到名為 sitepoint 的數(shù)據(jù)庫。 連接建立后我們要使用連接變量來對數(shù)據(jù)庫中的 employees 表進(jìn)行查詢。 現(xiàn)在運行 app.js (通過 grunt-watch 或者在終端輸入 node app.js),你可以看到終端輸出從數(shù)據(jù)庫返回的數(shù)據(jù)。 從 MySQL 數(shù)據(jù)庫返回的數(shù)據(jù)可以通過遍歷 rows 對象來進(jìn)行解析。 創(chuàng)建 你可以在數(shù)據(jù)庫中執(zhí)行 insert 查詢,像這樣: 請注意到我們是如何通過回調(diào)參數(shù)來獲得剛插入那條記錄的 ID 的。 更新 類似地,在執(zhí)行 update 查詢的時候,通過 result.affectedRows 可得到受影響的行數(shù): 刪除 delete 查詢的操作也差不多: ![]() 高級用法 ![]() 我希望有辦法通過 mysql 模塊來處理存儲過程,以及轉(zhuǎn)義用戶輸入。 存儲過程 簡單的說,存儲過程是存儲在數(shù)據(jù)庫中,可以由數(shù)據(jù)庫引擎和連接上數(shù)據(jù)的程序語言調(diào)用的程序(例如,SQL 程序)。如果你需要復(fù)習(xí),請看看這篇不錯的文章。 先來為我們的 sitepoint 數(shù)據(jù)庫創(chuàng)建一個存儲過程,它用于獲取所有員工的詳情。我們把它命名為 sp_getall。為了做這件事,你需要某種數(shù)據(jù)庫接操作界面。我使用 phpMyAdmin。在 sitepoint 數(shù)據(jù)庫中運行下面的查詢: 它會將程序保存在 information_schema 數(shù)據(jù)庫的 ROUTINGS 表中。 下一步,建立連接并使用連接對象調(diào)用存儲過程,像這樣: 保存修改并運行。運行的時候你可以看到從數(shù)據(jù)庫返回的數(shù)據(jù)。 這些數(shù)據(jù)包括一些附加信息,比如影響的行數(shù),insertId 等。你需要對返回數(shù)據(jù)的第 0 個元素進(jìn)行遍歷以獲取員工詳情信息。 現(xiàn)在考慮一個需要輸入?yún)?shù)的存儲過程。 我們可以在調(diào)用存儲過程的時候傳入?yún)?shù): 多數(shù)時候,如果我們想在數(shù)據(jù)庫中插入一條記錄,需要將插入記錄的 ID 作為輸出參數(shù)返回出來。考慮接下來用于插入數(shù)據(jù)的存儲過程,它有一個輸出參數(shù): 為了調(diào)用含有輸出參數(shù)的存儲過程,我們需要在創(chuàng)建連接時調(diào)用多個程序。因此,修改連接,設(shè)置執(zhí)行多個語句為 true。 然后在調(diào)用存儲過程的時候,設(shè)置并傳入一個輸出參數(shù)。 在上面的代碼中,我們設(shè)置了輸出參數(shù) @employee_id 并在調(diào)用存儲過程的時候?qū)⑵鋫魅?。一旦調(diào)用完成,我們需要使用 select 查詢輸出參數(shù)來獲取返回的 ID。 運行 app.js。如果執(zhí)行成功你可以看到 select 查詢的輸出參數(shù)和各種其它信息。通過 rows[2] 可獲得輸出參數(shù)的值。 轉(zhuǎn)義用戶輸入 為了避免 SQL 注入攻擊,你應(yīng)該總是轉(zhuǎn)義來自用戶的任何數(shù)據(jù),然后再把它用于 SQL 查詢。來演示一下為什么: 這看起來并沒有什么問題,它會返回正確的結(jié)果: 不過,如果我們將 userLandVariable 改為: 居然訪問了整個數(shù)據(jù)集。如果我們再改為這樣: 這下麻煩大了! 好消息是有辦法處理這類問題。你只需要使用 mysql.escape 方法:
![]() 為什么不簡單地使用 ORM? ![]() 你可能注意到了,評論中有人建議使用 ORM。在詳述這個方法的優(yōu)缺點之前,我先看看 ORM 是什么。下面是來自 Stack Overflow 的回答。
因此,這種方法基本上意味著你會使用 ORM 領(lǐng)域相關(guān)的語言來編寫數(shù)據(jù)庫邏輯,而不是我們一直在討論的普通方法。下面以 Sequelize 為例: 對比: 使用 ORM 對你是否有意義,取決于很多與你工作相關(guān)的因素,比如你在做什么以及為誰做。一方面,ORM 的形式使開發(fā)更為高效,從某種程序上來說,它抽象了大部分的 SQL 因而不需要團(tuán)隊中的每個人都去了解如何編寫高效的數(shù)據(jù)庫查詢。它也很容易遷移到不同的數(shù)據(jù)庫軟件,因為你是在抽象層次上進(jìn)行開發(fā)。 然而,從另一方面來說,由于不理解 ORM 是如何做的,所以可能會編寫出一些混亂和低效的 SQL。性能也會是一個大問題,畢竟優(yōu)化不通過 ORM 的查詢要容易得多。 到底采用哪一種方法,決定權(quán)在你,但是如果正在做這個決定,請看看這個 Stack Overflow 的帖子:為什么應(yīng)該使用 ORM?,以及 SitePoint 上的:你可能不知道的 3 個 JavaScript ORM。 ![]() 小結(jié) ![]() 本教程中只涉及到了 MySQL 客戶端的皮毛。我推薦你去閱讀官方文檔以了解更詳細(xì)的信息。當(dāng)然也有別的選擇,比如 node-mysql2 和 node-mysql-libmysqlclient。 你是否已經(jīng)在 Node.js 中用過這些庫來連接到 MySQL?我很想聽人說說這些庫。請在下面的評論中告訴我們你的想法、建議以及更正意見!
|
|