淺談MVC–Node中如何使用ORM?
- 2019 年 10 月 11 日
- 筆記
在正常的開發中,大部分都會使用MVC為主要的系統架構模式。而Model一般包含了複雜的業務邏輯以及數據邏輯,因為Model中邏輯的複雜度,所以我們有必要降低系統的耦合度。通常情況下,我們如果直接使用JDBC操作資料庫,業務邏輯和數據存取邏輯是混在一起的。我們一般一個功能的邏輯可能如下所示:
- 接收客戶端的參數,建立資料庫的連接。
- 根據功能組裝sql語句,然後創建Statement對象。
- 使用Connection對象執行sql語句,得結果集ResultSet。
- 循環讀取結果集的數據,然後根據數據進行業務邏輯處理。
- 如果還有進一步的需求,再組裝新的sql語句進行執行。
- 執行結束關閉資料庫連接。
可以看到上面業務邏輯和數據存取邏輯是緊密耦合在一起的,如果需要修改需求,那工作量則是成倍的增長。所以有必要將業務邏輯以及數據存取邏輯分離開來,所以產生了ORM這麼一個對象與數據之間的映射技術。簡單來說ORM就是通過實例對象的語法,完成對關係型資料庫操作的技術,是對象-關係映射的縮寫。而本篇文章主要介紹一個NodeJS環境下的ORM框架—Sequelize。
首先,我們基於腳手架快速搭建一個express項目,執行命令:
express testORM

進入項目並且安裝依賴:
npm install
首先,我們先改變一下項目目錄結構:
- 項目已有目錄routes下存放路由文件。
- 根目錄下創建config.js,存放常量參數。
- 根目錄下創建contonller文件夾,在contonller下創建db.js,裡面封裝Sequelize連接資料庫的操作。
- 根目錄下創建db文件夾,在contonller下創建pay_goods.js,裡面定義數據類型,封裝資料庫存取的操作。
- 根目錄下創建service文件夾,在service下創建pay_goods.js,裡面對數據進行業務邏輯處理。
- 根目錄下創建utils文件夾,用來存放全局方法。
所以我們生成的項目最終項目結構如下:

首先要使用SequeLize,我們需要安裝sequelize和mysql2包。命令如下:
npm install --save-dev sequelize mysql2
首先在config.js中配置資料庫連接常量:

然後進入contonller/db.js初始化資料庫連接:

然後進入db/pay_goods.js中,在這裡負責對數據表進行數據類型定義以及數據讀取操作。我們首先使用sequelize.define()針對pay_goods表定義數據類型:

define()方法共存在三個參數:
- 參數1:表示映射的資料庫表名
- 參數2:對表中每一個對象進行數據類型定義。
- 參數3:對選填參數配置
這裡對於Sequelize中的數據類型直接貼下文檔中提供的:

數據類型定義需要注意一點,如果我們有插入操作,Sequelize默認會增加createdAt欄位和updateAt欄位,所以說如果我們不需要這兩個欄位我們可以在參數3選填參數添加timestamps為false關閉添加這兩個參數的操作。
對映射的數據表定義好數據類型,接下來我們可以寫幾個簡單的資料庫存取操作。Sequelize提供的API是非常豐富的,一篇文章不可能一一講解,所以我就選幾個比較通用的API。首先我們通過定義的數據類型調用create()可以保存數據,這裡我們在外層封裝一層function可以接受來自路由層的參數:

接下來進入utils/common.js實現一個獲取客戶端傳參的全局方法:

進入routes/users.js實現路由,調用全局方法paramAll()獲取客戶端傳參,然後參數處理等業務邏輯我們放在service下的pay_goods.js,所以調用service/pay_goods.js封裝的參數處理方法calcBalance()對參數進行處理:

參數處理完返回給路由層,然後調用db中我們剛才封裝的saveOrder()保存數據:

上面就完成的實現了一個插入數據的API,我們不需要手動書寫sql語句。而且將業務邏輯和數據存取邏輯完全獨立。接下來我們可以再看幾個查詢語句:

可以看到我們查詢一共寫了三個典型的示例方法,我們來分別看看是查詢什麼樣的數據:
- findAll():查詢多條數據,傳入一個json對象,json對象中可以對查詢條件進行限制,比如我示例程式碼中使用attributes傳入要查詢的數據列數組,使用where傳入where條件語句的參數限制,使用limit和offset參數可以進行分頁操作,使用order可以根據某個數據列操作等。
- findByPk():通過id查詢對應數據,id一般為主鍵,所以只會返回一條數據,而且參數只能傳入id。
- findOne():只能查詢一條語句,一樣可以指定findAll()中的各種條件,但是只會返回符合條件的第一條數據。
到這裡我們對於Sequelize的基礎操作就差不多了解了,接下來來看看Sequelize封裝sql如何鏈式調用多個資料庫操作,因為Sequelize是基於Promise的ORM框架,所以我們很簡單的使用鏈式調用資料庫讀取操作實現多個資料庫操作:

到這裡我們就可以實現MVC架構,將資料庫數據讀取操作封裝到db層,將路由操作封裝到routes層,將業務邏輯操作封裝到service下。有利於項目的不斷迭代開發。