最近開始接觸數據庫,如今廣泛用的都是Mysql
數據庫,簡單的瞭解了一下sql
語句,沒有太深刻的學習,而後就開始找相關的ORM
框架,而後鎖定了Sequelize
,我的感受很強大,搜索了一些文檔,可是很讓人費解,講的每一部分都是那麼的官方,不太容易理解,記錄一下學習路程。本文檔以koa
+Sequelize
進行編碼測試。前端
準備工做
在嘗試使用Sequelize
以前先確認是否安裝了Mysql
數據庫,安裝node
,這裏使用的Mysql 5.6
版本。node
首先要建立一個項目執行命令以下:mysql
mkdir 文件夾名稱 cd 文件夾名稱 npm init -y // 直接略過全部問答,所有采用默認答案
在開始以前首先要安裝相關依賴:sql
// 安裝 sequelize koa mysql2 npm install --save-dev sequelize koa mysql2
注意:這裏是mysql2數據庫
創建鏈接
建立main.js
文件,分別引入koa
和sequelize
創建與mqsql
數據庫鏈接。在實例化Sequelize
時須要配置一些參數,第一個接收的參數時數據庫的名稱,第二個是用戶名,第三個是密碼,第四項是鏈接mysql
的相關配置。npm
const Koa = require("koa"); const Sequelize = require("sequelize"); const app = new Koa(); const mysqlConfig ={ host: 'localhost', // 接數據庫的主機 port: '3306', // 接數據庫的端口 protocol: 'tcp', // 鏈接數據庫使用的協議 dialect: 'mysql', // 使用mysql pool: { max: 5, // 最大鏈接數量 min: 0, // 最小鏈接數量 idle: 10000 // 鏈接空置時間(毫秒),超時後將釋放鏈接 }, retry: { // 設置自動查詢時的重試標誌 max: 3 // 設置重試次數 }, omitNull: false, // null 是否經過SQL語句查詢 timezone: '+08:00' // 解決時差 - 默認存儲時間存在8小時偏差 }; const sequelize = new Sequelize('aarontest', 'root', '123456',mysqlConfig ); app.listen(3000);
經過上述代碼就已經與Mysql
創建了鏈接。這個地方沒有什麼能夠講的,按照上述進行配置就能夠了。test
數據庫不必定要存在不存在也是能夠正常創建鏈接的。配置參數還有不少,這裏只說了一些經常使用的,就很少贅述了。若是以爲上述方法比較麻煩能夠經過也提供了其餘方法進行鏈接:json
const sequelize = new Sequelize('mysql://root:123456@localhost:3306/aarontest', { ...mysqlConfig });
這種鏈接方式與mongoose
鏈接方法差很少,以致於具體使用哪一種方式仍是要根據我的的編碼習慣來決定。後端
創建model
sequelize
是經過define
方法創建模型的,Model
至關於數據庫中的表,該對象不能經過構造函數實例化,而只能經過sequelize.define()
或sequelize.import()
方法建立。api
const AaronTest = sequelize.define('project', { title: Sequelize.STRING, description: Sequelize.TEXT })
經過上面的方法建立好model
以後,使用Navicat
(數據庫可視化工具)仍然沒法看到咱們所建立的表,尷尬。。。sequelize
提供了一個sync()
方法能夠同步模型到數據庫。使用該方法的時候必定要注意所鏈接的數據庫必定要存在
不然會報錯。數組
define
方法接收三個參數,第一個參數爲表名稱,第二個爲所須要建立的數據庫字段,第三個參數是相關表配置。
const AaronTest = sequelize.define('project', { title: Sequelize.STRING, description: Sequelize.TEXT }); AaronTest.sync();
這樣model
所建立的字段就被同步到了數據庫中,一樣相對應的表也被建立好了,須要注意經過這種方式同步的表會在表名稱後面添加一個s
做爲複數。同步數據庫是會默認添加兩個字段createdAt
和updatedAt
有的時候可能不須要這兩個字段。這個時候須要在第三個字段中添加timestamps
爲false
默認爲true
。
const AaronTest = sequelize.define('project', { title: Sequelize.STRING, description: Sequelize.TEXT },{ timestamps: false })
上面能夠看出經過Sequelize.STRING
設置當前字段的類型,Sequelize
提供了不少數據類型供咱們進行使用:
類型 | 說明 |
---|---|
STRING | 將字段指定爲變長字符串類型,默認長度爲 255。Sequelize.STRING(64) |
CHAR | 將字段指定爲定長字符串類型,默認長度爲 255。Sequelize.CHAR(64) |
TEXT | 將字段指定爲(無)有限長度的文本列。可用長度:tiny, medium, long,Sequelize.TEXT('tiny') |
INTEGER | 32位整型,可用屬性:UNSIGNED,ZEROFILL,Sequelize.INTEGER('UNSIGNED') |
BOOLEAN | 小數,接受一個或兩個參數表示精度,Sequelize.BOOLEAN() |
TIME | 指定爲時間類型列,Sequelize.TIME() |
DATE | 指定爲日期時間類型列,Sequelize.DATE() |
DATEONLY | 指定爲日期類型列,Sequelize.DATEONLY() |
HSTORE | 指定爲鍵/值類型列,僅Postgres適用,Sequelize.HSTORE() |
JSON | 指定爲JSON字符串類型列,僅Postgres適用,Sequelize.JSON() |
JSONB | 指定爲預處理的JSON數據列,僅Postgres適用,Sequelize.JSONB() |
NOW | 一個表示當前時間戳的默認值,Sequelize.NOW() |
UUID | UUID類型列,其默認值能夠爲UUIDV1或UUIDV4,Sequelize.UUID() |
ENUM | 枚舉類型,Sequelize.ENUM() |
ARRAY | 數組類型,僅Postgres適用,Sequelize.ARRAY() |
設定model的時候在添加第三個參數能夠對當前model
進行二次設置,以使數據庫更增強壯,經常使用字段以下
當建立model
的時候可能須要有些附加屬性,好比主鍵
,自增
,不能爲null
,默認值等等,能夠在建立model
的時候進行手動設置。
除了這些之外Sequelize
在定義model
的時候,還提供了一個validate
屬性,能夠爲添加的字段進行校驗處理:
字段 | 說明 | 值類型 |
---|---|---|
is | 存儲值必須知足正則 | 正則 |
not | 除正則以外的值 | 布爾 |
isEmail | 是否爲郵箱 | 布爾 |
isUrl | 檢查Url格式 | 布爾 |
isIP | 檢查 IPv4 或 IPv6 格式 | 布爾 |
isIPv4 | 檢查 IPv4 | 布爾 |
isIPv6 | 檢查 IPv6 | 布爾 |
isAlpha | 不能使用字母 | 布爾 |
isAlphanumeric | 只容許字母數字字符 | 布爾 |
isNumeric | 只能使用數字 | 布爾 |
isInt | 只能是整數 | 布爾 |
isFloat | 只能是浮點數 | 布爾 |
isDecimal | 檢查數字 | 布爾 |
isLowercase | 檢查小寫字母 | 布爾 |
isUppercase | 檢查大寫字母 | 布爾 |
notNull | 不容許null | 布爾 |
isNull | 只能爲null | 布爾 |
notEmpty | 不能空字符串 | 布爾 |
equals | 只能使用指定值 | 字符串 |
contains | 必須包含子字符串 | 字符串 |
notIn | 不能是數組中的任意一個值 | 數組 |
isIn | 只能是數組中的任意一個值 | 數組 |
notContains | 不能包含子字符串 | 字符串 |
len | 值的長度必在 2 和 10 之間 | 數組 |
isUUID | 只能是UUID | 數字 |
isDate | 只能是日期字符串 | 布爾 |
isAfter | 只能使用指定日期以後的時間 | 字符串 |
isBefore: | 只能使用指定日期以前的時間 | 字符串 |
max | 容許的最大值 | 數字 |
min | 容許的最小值 | 數字 |
isArray | 不能使用數組 | 布爾 |
isCreditCard | 檢查是有效的信用卡 | 布爾 |
除了上面的校驗方法之外還提供了自定義校驗方法,使用isEven
去定義一個函數,其函數的第一個參數就是所存如的值:
const AaronTest = sequelize.define('project', { title: Sequelize.STRING, description: { type:Sequelize.TEXT, validate:{ isEven: function(value) { if(parseInt(value) % 2 != 0) { throw new Error('Only even values are allowed!') } } } } },{ timestamps: false })
上面說過使用sequelize.import()
也能夠建立model
這個方法實際上是模型導入,經過文件導入模型定義。檢查模型是否已經定義。被導入的模型會被緩存,因此屢次導入並不會重複加載,path表示要導入文件的路徑,若是使用相對路徑會自動轉換爲絕對路徑。
const AaronTest = sequelize.import('../model/user.js');
user.js
module.exports = function(sequelize, DataTypes) { return sequelize.define("project", { name: DataTypes.STRING, description: DataTypes.TEXT }) }
CRUD
CRUD:是指在作計算處理時的增長(Create)、讀取(Read)、更新(Update)和刪除(Delete)幾個單詞的首字母簡寫。crud主要被用在描述軟件系統中數據庫或者持久層的基本操做功能。
建立
建立數據的方法有不少種,這裏簡單的介紹一些經常使用的:
第一種:
先建立數據實例,而後調用實例的save
方法,完成數據存儲。
const Aaron = AaronTest.build({ 'title': `後端 | ${Math.random()}`, 'description': '技術部' }); Aaron.save().then((result) => { // 成功 console.log(result) }).catch((error) => { // 失敗 console.log(error) })
第二種:
經過靜態create
方法
const user = AaronTest.create({ 'title': `前端 | ${Math.random()}`, 'description': '網絡部' }).then(function(result) { // 成功 console.log(result) }).catch(function(error) { // 失敗 console.log(error) });
讀取
經過findAll
方法讀取數據。
AaronTest.findAll({ where: { description: '網絡部' }, limit: 10, offset: 0 }).then(function(result) { // success console.log(result) }).catch(function(error) { // error console.log(error) });
經過上述方法建立的數據能夠直接做爲返回結果返回給前臺,可是若是對查詢到的結果進行數據操做時不行的,由於查詢到的結果是sequelize
處理過的模型,若是想對其操做須要在參數中添加row:true
屬性。
AaronTest.findAll({ where: { description: '網絡部' }, limit: 10, // 查詢多少條 offset: 0, // 查詢開始位置 raw:true }).then(function(result) { // success console.log(result) }).catch(function(error) { // error console.log(error) });
添加row:true
返回的則是一個沒有被包裝過的數組了。在項目過程當中須要查詢一下當前所查詢的數據共有多少條返回給前端。
AaronTest.count({ where:{ description: '網絡部' } }).then().then(function(result) { // success console.log(result) }).catch(function(error) { // error console.log(error) });
使用這種方法是確實能夠查詢到想要的結果,可是不管是先查詢列表仍是先查詢總數,都須要對數據庫進行兩次查詢很繁瑣。sequelize
提供了一個很方便的方法。
AaronTest.findAndCountAll({ where: { description: '網絡部' }, limit: 10, offset: 0, raw:true, attributes:["id", "title"] // 須要查詢出的字段 }).then(function(result) { // success console.log(result) }).catch(function(error) { // error console.log(error) });
經過上面的方法則能夠查詢到總數以及條件範圍內的數據,一箭雙鵰。查詢結果返回的是一個json
對象,其包括cont
和rows
兩個屬性,分別是總數和數據。很舒服有沒有。
以上方式是查詢列表,查詢單條數據使用其餘方法:
AaronTest.findOne({ where:{ id:6 }, raw:true, attributes:["id", "title"] }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
更新
修改數據能夠直接調用靜態的update
方法,經過where
條件查詢,對其搜索到的數據進行查詢,並對查詢到的數據進行更改。
AaronTest.update({ description: '前端部', title:`前端 | ${Math.random()}` },{ where:{ description: "網絡部" } }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
該方法修改全部查詢的到的數據,返回結果爲數組形式,數據只有一個值,也就是數組的第0
項,則是N
條數據修改爲功。
刪除
刪除操做經過destroy
方法,一樣也是經過where
條件查詢,對所查詢數據進行刪除。
AaronTest.destroy({ where: { description: "UI部", } }).then(function(result) { console.log(result) }).catch(function(error) { console.log(error) });
當刪除成功後,返回結果爲Number
,刪除多少條數據,若是沒有刪除則會返回0
。此方法屬於物理刪除,刪除後沒法進行恢復。
查詢參數
CRUD
操做過程當中,都少不了的就是查詢,細心的應該能夠看的出,上面的例子中查詢的時候多多少少的對其進行了一些小的改動。Sequelize
中有兩種查詢:使用Model
(模型)中的方法查詢和使用sequelize.query()
進行基於SQL
語句的原始查詢。上面用到的是Model
查詢方式,接下來就詳細的介紹一些經常使用的參數以及其表明的意義。
attributes - 屬性與查詢字段
查詢時,若是隻須要查詢模型的部分屬性,能夠在經過在查詢選項中指定attributes
實現。該選項是一個數組參數,在數組中指定要查詢的屬性便可,這個字段在上面進行查詢的時候已經使用過了。
AaronTest.findOne({ where:{ id:6 }, raw:true, attributes:["id", "title", "description"] }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
查詢屬性(字段)能夠經過傳入一個嵌套數據進行重命名,這裏須要強調一下重命名所指的是對查詢出的數據鍵值進行重命名處理,而不是更改數據表中的字段名稱。
AaronTest.findOne({ where:{ id:2 }, attributes:["id", ["title","t"]], raw:true }).then((result) => { console.log(result) }).catch((error) => { console.log(error) }) // 注意這裏t ↓ // { id: 2, t: '前端 | 0.8765218593370694' }
經過sequelize.fn
方法能夠進行聚合查詢,我的以爲這個方法不太經常使用,可是仍是簡單的介紹一下,這種查詢方式是向當前查詢內容中添加一個新的屬性,而且查詢的是列表仍是查詢單條數據。
應用場景:
好比有不少商品,每一個商品都有本身的分類,根據id
進行查詢了一個商品,可是與其同類的商品有多少?就可使用這個方法添加進去。下面例子中的count
則是添加進去屬性的鍵。
AaronTest.findAll({ where:{ id:2 }, attributes: [ "id", ["title","t"], [sequelize.fn('COUNT', sequelize.col('id')), 'count'] ], raw:true }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
可能有一種狀況,當前所須要查詢的表字段太多,可是隻有一兩個數據不想要,在attributes
數組中添加很長的字段名稱,這樣會顯得代碼很臃腫。attributes
不光能夠爲數組,還能夠爲對象在對象存在exclude
這個屬性,這個屬性就是剔除掉那些不想要的屬性。
AaronTest.findOne({ where:{ id:2 }, attributes:{ exclude: ['id'] }, raw:true }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
where - 指定篩選條件
上面的那麼多例子中where
出現的次數最多了,除了增長數據不須要,其餘的都須要用到where
條件,能夠指定一個where
選項以指定篩選條件,where
是一個包含屬性/值對對象,sequelize
會根據此對象生產查詢語句的篩選條件。
where
的基礎用法也就向上面那樣,針對某些特定的條件進行查詢處理。
AaronTest.findOne({ where:{ id:2 }, attributes:{ exclude: ['id'] }, raw:true }).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
就像上面那樣簡單的查詢沒法知足全部的業務需求,Sequelize
還提供了操做符以知足更多的查詢條件,經常使用的操做符以下:
$and: {a: 5} // AND (a = 5) $or: [{a: 5}, {a: 6}] // (a = 5 OR a = 6) $gt: 6, // > 6 $gte: 6, // >= 6 $lt: 10, // < 10 $lte: 10, // <= 10 $ne: 20, // != 20 $not: true, // IS NOT TRUE $between: [6, 10], // BETWEEN 6 AND 10 $notBetween: [11, 15], // NOT BETWEEN 11 AND 15 $in: [1, 2], // IN [1, 2] $notIn: [1, 2], // NOT IN [1, 2] $like: '%hat', // LIKE '%hat' $notLike: '%hat' // NOT LIKE '%hat' $iLike: '%hat' // 包含'%hat' (case insensitive) (PG only) $notILike: '%hat' // 不包含'%hat' (PG only) $like: { $any: ['cat', 'hat']} // 像任何數組['cat', 'hat'] -也適用於iLike和notLike
limit/offset - 分頁與限制返回結果數
在進行列表查詢時,不能把查詢道德全部數據所有返回出去,須要對數據進行分頁處理。
// 獲取 10 條數據(實例) AaronTest.findAll({ limit: 10 }) // 跳過 8 條數據(實例) AaronTest.findAll({ offset: 8 }) // 跳過 5 條數據並獲取其後的 5 條數據(實例) AaronTest.findAll({ offset: 5, limit: 5 })
查詢排序
order
選項用於查詢結果的排序數據。排序時應該傳入一個包含屬性-排序方向的元組/數組,以保證正確的轉義:
AaronTest.findAll({ order: [ // 轉義 username 並對查詢結果按 DESC 方向排序 ['username', 'DESC'], // 按 max(age) 排序 sequelize.fn('max', sequelize.col('age')), // 按 max(age) DESC 排序 [sequelize.fn('max', sequelize.col('age')), 'DESC'], // 按 otherfunction(`col1`, 12, 'lalala') DESC 排序 [sequelize.fn('otherfunction', sequelize.col('col1'), 12, 'lalala'), 'DESC'], // 按相關聯的User 模型的 name 屬性排序 [User, 'name', 'DESC'], // 按相關聯的User 模型的 name 屬性排序並將模型起別名爲 Friend [{model: User, as: 'Friend'}, 'name', 'DESC'], // 按相關聯的User 模型的嵌套關聯的 Company 模型的 name 屬性排序 [User, Company, 'name', 'DESC'], ] // 如下全部聲明方式都會視爲字面量,應該當心使用 order: 'convert(user_name using gbk)' order: 'username DESC' order: sequelize.literal('convert(user_name using gbk)') })
上面說的這些對於SQL
語句瞭解一些,都是很容理解,有些API
不經常使用也就沒些,詳細能夠查看中文文檔。
SQL語句查詢
原始查詢中有兩種替換查詢參數的方法,以:開頭的參數的形式替換或以不命名以?替換。在選項對象中傳遞參數:
// 這裏是sequelize,並非model sequelize.query('SELECT * FROM projects WHERE id = ?', { replacements: ['active'], type: sequelize.QueryTypes.SELECT } ).then((result) => { console.log(result) }).catch((error) => { console.log(error) })
總結
以上是對sequelize
的api
進行了整理,雖然不太全面,熟練掌握上述API
能夠作一個項目了,有關sequelize
的更多的用法我也在繼續爬坑中,可能文章中有些許錯誤,你們能夠在下方留言,我會盡快作出改正。感謝你們的閱讀。