項目開發(fā)中,經(jīng)常要操作數(shù)據(jù)庫,如:增刪改查等操作。模型就是為了方便操作數(shù)據(jù)庫進行的封裝,一個模型對應(yīng)數(shù)據(jù)庫中的一個數(shù)據(jù)表。
目前支持的數(shù)據(jù)庫有:Mysql
,MongoDB
和 SQLite
。
可以在項目目錄下通過命令 thinkjs model [name]
來創(chuàng)建模型:
thinkjs model user;
執(zhí)行完成后,會創(chuàng)建文件 src/common/model/user.js
。
默認情況下模型文件會創(chuàng)建在 common
模塊下,如果想創(chuàng)建在其他的模塊下,創(chuàng)建時需要指定模塊名:
thinkjs model home/user
模型配置如下,可以在 src/common/config/db.js
中進行修改:
export default {
type: "mysql", //數(shù)據(jù)庫類型
host: "127.0.0.1", //數(shù)據(jù)庫 host
port: "", //數(shù)據(jù)庫端口,默認為 3306
name: "", //數(shù)據(jù)庫名
user: "", //賬號
pwd: "", //密碼
prefix: "think_", //數(shù)據(jù)表前綴,如果不想要數(shù)據(jù)表前綴,可以設(shè)置為空
encoding: "utf8", //數(shù)據(jù)庫編碼
nums_per_page: 10, //每頁顯示的條數(shù)
log_sql: true, //是否記錄執(zhí)行的 sql 語句
log_connect: true, //是否記錄數(shù)據(jù)庫連接信息
cache: { // 數(shù)據(jù)庫查詢緩存配置
on: true,
type: "",
timeout: 3600
}
};
也可以在不同的模塊下進行不同的模型配置,此時需要設(shè)置模塊下對應(yīng)的模型配置,配置文件為src/[module]/config/db.js
。
默認情況下,模型名和數(shù)據(jù)表名都是一一對應(yīng)的。假設(shè)數(shù)據(jù)表前綴是 think_
,那么 user
模型對應(yīng)的數(shù)據(jù)表為 think_user
,user_group
模型對應(yīng)的數(shù)據(jù)表為 think_user_group
。
如果需要修改,可以通過下面 2 個屬性進行:
tablePrefix
表前綴tableName
表名,不包含前綴export default class extends think.model.base {
init(...args){
super.init(...args);
this.tablePrefix = ""; //將數(shù)據(jù)表前綴設(shè)置為空
this.tableName = "user2"; //將對應(yīng)的數(shù)據(jù)表名設(shè)置為 user2
}
}
module.exports = think.model({
tablePrefix: "", //直接通過屬性來設(shè)置表前綴和表名
tableName: "user2",
init: function(){
this.super("init", arguments);
}
})
模型實例化在不同的地方使用的方式有所差別,如果當前類含有 model
方法,那可以直接通過該方法實例化,如:
export default class extends think.controller.base {
indexAction(){
let model = this.model("user");
}
}
否則可以通過調(diào)用 think.model
方法獲取實例化,如:
let getModelInstance = function(){
let model = think.model("user", think.config("db"), "home");
}
使用 think.model
獲取模型的實例化時,需要帶上模型的配置。
模型中提供了很多鏈式調(diào)用的方法(類似 jQuery 里的鏈式調(diào)用),通過鏈式調(diào)用方法可以方便的進行數(shù)據(jù)操作。鏈式調(diào)用是通過返回 this
來實現(xiàn)的。
export default class extends think.model.base {
/**
* 獲取列表數(shù)據(jù)
*/
* getList(){
let data = yield this.field("title, content").where({
id: [">", 100]
}).order("id DESC").select();
...
}
}
模型中支持鏈式調(diào)用的方法有:
where
, 用于查詢或者更新條件的定義table
, 用于定義要操作的數(shù)據(jù)表名稱alias
, 用于給當前數(shù)據(jù)表定義別名data
, 用于新增或者更新數(shù)據(jù)之前的數(shù)據(jù)對象賦值field
, 用于定義要查詢的字段,也支持字段排除order
, 用于對結(jié)果進行排序limit
, 用于限制查詢結(jié)果數(shù)據(jù)page
, 用于查詢分頁,生成 sql 語句時會自動轉(zhuǎn)換為 limitgroup
, 用于對查詢的 group 支持having
, 用于對查詢的 having 支持join
, 用于對查詢的 join 支持union
, 用于對查詢的 union 支持distinct
, 用于對查詢的 distinct 支持cache
用于查詢緩存使用 add
方法可以添加一條數(shù)據(jù),返回值為插入數(shù)據(jù)的 id。如:
export default class extends think.controller.base {
* addAction(){
let model = this.model("user");
let insertId = yield model.add({name: "xxx", pwd: "yyy"});
}
}
使用 addMany
方法可以添加一條數(shù)據(jù),如:
export default class extends think.controller.base {
* addAction(){
let model = this.model("user");
let insertId = yield model.addMany([
{name: "xxx", pwd: "yyy"},
{name: "xxx1", pwd: "yyy1"}
]);
}
}
數(shù)據(jù)庫設(shè)計時,我們經(jīng)常需要把某個字段設(shè)為唯一,表示這個字段值不能重復(fù)。這樣添加數(shù)據(jù)的時候只能先去查詢下這個數(shù)據(jù)值是否存在,如果不存在才進行插入操作。
模型中提供了 thenAdd
方法簡化這一操作。
export default class extends think.controller.base {
* addAction(){
let model = this.model("user");
//第一個參數(shù)為要添加的數(shù)據(jù),第二個參數(shù)為添加的條件,根據(jù)第二個參數(shù)的條件查詢無相關(guān)記錄時才會添加
let result = yield model.thenAdd({name: "xxx", pwd: "yyy"}, {name: "xxx"});
// result returns {id: 1000, type: "add"} or {id: 1000, type: "exist"}
}
}
更新數(shù)據(jù)使用 update
方法,返回值為影響的行數(shù)。如:
export default class extends think.controlle.base {
* updateAction(){
let model = this.model("user");
let affectedRows = yield model.where({name: "thinkjs"}).update({email: "admin@thinkjs.org"});
}
}
模型中提供了多種方式來查詢數(shù)據(jù),如:查詢單條數(shù)據(jù),查詢多條數(shù)據(jù),讀取字段值,讀取最大值,讀取總條數(shù)等。
可以使用 find
方法查詢單條數(shù)據(jù),返回值為對象。如:
export default class extends think.controller.base {
* listAction(){
let model = this.model("user");
let data = yield model.where({name: "thinkjs"}).find();
//data returns {name: "thinkjs", email: "admin@thinkjs.org", ...}
}
}
如果數(shù)據(jù)表沒有對應(yīng)的數(shù)據(jù),那么返回值為空對象 {}
,可以通過 think.isEmpty
方法來判斷返回值是否為空。
可以使用 select
方法查詢多條數(shù)據(jù),返回值為數(shù)據(jù)。如:
export default class extends think.controller.base {
* listAction(){
let model = this.model("user");
let data = yield model.limit(2).select();
//data returns [{name: "thinkjs", email: "admin@thinkjs.org"}, ...]
}
}
如果數(shù)據(jù)表中沒有對應(yīng)的數(shù)據(jù),那么返回值為空數(shù)組 []
,可以通過 think.isEmpty
方法來判斷返回值是否為空。
頁面中經(jīng)常遇到按分頁來展現(xiàn)某些數(shù)據(jù),這種情況下就需要先查詢總的條數(shù),然后在查詢當前分頁下的數(shù)據(jù)。查詢完數(shù)據(jù)后還要計算有多少頁。模型中提供了 countSelect
方法來方便這一操作,會自動進行總條數(shù)的查詢。
export default class extends think.controller.base {
* listAction(){
let model = this.model("user");
let data = yield model.page(this.get("page"), 10).countSelect();
}
}
返回值格式如下:
{
numsPerPage: 10, //每頁顯示的條數(shù)
currentPage: 1, //當前頁
count: 100, //總條數(shù)
totalPages: 10, //總頁數(shù)
data: [{ //當前頁下的數(shù)據(jù)列表
name: "thinkjs",
email: "admin@thinkjs.org"
}, ...]
}
如果傳遞的當前頁數(shù)超過了頁數(shù)范圍,可以通過傳遞參數(shù)進行修正。true
為修正到第一頁, false
為修正到最后一頁,即: countSelect(true)
或 countSelect(false)
。
如果總條數(shù)無法直接查詢,可以將總條數(shù)作為參數(shù)傳遞進去,如: countSelect(1000)
,表示總條數(shù)有1000條。
可以使用 delete
方法來刪除數(shù)據(jù),返回值為影響的行數(shù)。如:
export default class extends think.controller.base {
* deleteAction(){
let model = this.model("user");
let affectedRows = yield model.where({id: [">", 100]}).delete();
}
}
為了性能優(yōu)化,項目中經(jīng)常要對一些從數(shù)據(jù)庫中查詢的數(shù)據(jù)進行緩存。如果手工將查詢的數(shù)據(jù)進行緩存,勢必比較麻煩,模型中直接提供了 cache
方法來設(shè)置查詢緩存。如:
export default class extends think.model.base {
getList(){
//設(shè)定緩存 key 和緩存時間
return this.cache("get_list", 3600).where({id: {">": 100}}).select();
}
}
上面的代碼為對查詢結(jié)果進行緩存,如果已經(jīng)有了緩存,直接從緩存里讀取,沒有的話才從數(shù)據(jù)庫里查詢。緩存保存的 key 為 get_list
,緩存時間為一個小時。
也可以不指定緩存 key,這樣會自動根據(jù) SQL 語句生成一個緩存 key。如:
export default class extends think.model.base {
getList(){
//只設(shè)定緩存時間
return this.cache(3600).where({id: {">": 100}}).select();
}
}
緩存配置為模型配置中的 cache
字段,如:
export default {
cache: {
on: true,
type: "",
timeout: 3600
}
}
on
數(shù)據(jù)庫緩存配置的總開關(guān),關(guān)閉后即使程序中調(diào)用 cache
方法也無效。type
緩存配置類型,默認為內(nèi)存,支持的緩存類型請見 Adapter -> Cache。timeout
默認緩存時間。
模型中更多的操作方式請見相關(guān)的 API -> model。
更多建議: