這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
gf架構的資料庫ORM操作由gdb包提供支援,gdb包經過非常精心優雅的設計,提供了非常強大的組態管理、方法操作、鏈式操作、事務操作等功能。gdb包具體API說明文檔詳見:godoc 。本章節對gdb包的使用進行基本的介紹,包括:gdb包準系統介紹,組態管理功能說明,常見用法及常用操作樣本。
使用方式:
import "gitee.com/johng/gf/g/database/gdb"
資料庫配置
gdb資料結構:
type List []Map // 資料記錄列表 type Map map[string]interface{} // 資料記錄type Config map[string]ConfigGroup // 資料庫設定物件type ConfigGroup []ConfigNode // 資料庫分組配置// 資料庫配置項(一個分組配置對應多個配置項)type ConfigNode struct { Host string // 地址 Port string // 連接埠 User string // 帳號 Pass string // 密碼 Name string // 資料庫名稱 Type string // 資料庫類型:mysql, sqlite, mssql, pgsql, oracle(目前僅支援mysql,pgsql) Role string // (可選,預設為master)資料庫的角色,用於主從操作分離,至少需要有一個master,參數值:master, slave Charset string // (可選,預設為 utf-8)編碼,預設為 utf-8 Priority int // (可選)用於負載平衡的權重計算,當叢集中只有一個節點時,權重沒有任何意義 Linkinfo string // (可選)自訂連結資訊,當該欄位被設定值時,以上連結欄位(Host,Port,User,Pass,Name)將失效(該欄位是一個擴充功能,參考sql.Open參數)}
其中,Map和List用於資料表記錄操作,分別對應一條資料表記錄和資料表記錄列表;Config、ConfigGroup及ConfigNode用於資料庫組態管理,ConfigNode用於儲存一個資料庫節點資訊,ConfigGroup用於管理多個資料庫節點群組成的配置分組(一般一個分組對應一個業務資料庫叢集),Config用於管理多個ConfigGroup配置分組。
gdb主要特點:
- 支援多節點資料庫叢集管理,採用單例模式管理資料庫執行個體化對象;
- 支援對資料庫叢集分組管理,按照分組名稱擷取執行個體化的資料庫操作對象;
- 支援多種關係型資料庫管理,可通過ConfigNode.Type屬性進行配置(目前僅支援mysql和pgsql資料庫);
- 支援Master-Slave讀寫分離,可通過ConfigNode.Role屬性進行配置;
- 支援用戶端的負載平衡管理,可通過ConfigNode.Priority屬性進行配置,值越大,優先順序越高;
特別說明,gdb的組態管理最大的特點是,(同一進程中)所有的資料庫叢集資訊都使用同一個組態管理模組進行統一維護,不同業務的資料庫叢集配置使用不同的分組名稱進行配置和擷取。
配置方法
資料庫組態管理方法列表:
// 添加一個資料庫節點到指定的分組中func AddConfigNode(group string, node ConfigNode)// 添加一個配置分組到資料庫組態管理中(同名覆蓋)func AddConfigGroup(group string, nodes ConfigGroup)// 添加一個資料庫節點到預設的分組中(預設為default,可修改)func AddDefaultConfigNode(node ConfigNode)// 添加一個配置分組到資料庫組態管理中(預設分組為default,可修改)func AddDefaultConfigGroup(nodes ConfigGroup)// 設定資料庫配置為定義的配置資訊func SetConfig(c Config)// 設定預設的分組名稱func SetDefaultGroup(groupName string)
預設分組表示,如果擷取資料庫物件時不指定配置分組名稱,那麼gdb預設讀取的配置分組。例如:gdb.Instance()
可擷取一個預設分組的資料庫單例對象。
簡單的做法,我們可以通過gdb包的SetConfig
組態管理方法進行自訂的資料庫全域配置,例如:
gdb.SetConfig(gdb.Config { "default" : gdb.ConfigGroup { gdb.ConfigNode { Host : "127.0.0.1", Port : "3306", User : "root", Pass : "123456", Name : "test", Type : "mysql", Role : "master", Priority : 100, }, gdb.ConfigNode { Host : "127.0.0.2", Port : "3306", User : "root", Pass : "123456", Name : "test", Type : "mysql", Role : "master", Priority : 100, }, },})
設定檔
當然,gdb支援設定檔進行配置,這樣也便於項目的組態管理,具體請參見【ORM進階用法】章節。
資料庫操作
gdb資料庫操作的方法比較多,具體詳見godoc,以下僅對一些常用的方法進行介紹。
方法操作
// SQL操作方法,返回原生的標準庫sql對象Query(query string, args ...interface{}) (*sql.Rows, error)Exec(query string, args ...interface{}) (sql.Result, error)Prepare(query string) (*sql.Stmt, error)// 資料表記錄查詢:// 查詢單條記錄、查詢多條記錄、查詢單個欄位值(鏈式操作同理)GetAll(query string, args ...interface{}) (List, error)GetOne(query string, args ...interface{}) (Map, error)GetValue(query string, args ...interface{}) (interface{}, error)// 開啟事務操作Begin() (*Tx, error)// 資料單條操作Insert(table string, data Map) (sql.Result, error)Replace(table string, data Map) (sql.Result, error)Save(table string, data Map) (sql.Result, error)// 資料大量操作BatchInsert(table string, list List, batch int) (sql.Result, error)BatchReplace(table string, list List, batch int) (sql.Result, error)BatchSave(table string, list List, batch int) (sql.Result, error)// 資料修改/刪除Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error)Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error)// 建立鏈式操作對象(Table為From的別名)Table(tables string) (*DbOp)From(tables string) (*DbOp) // 關閉資料庫Close() error
需要說明一下Insert/Replace/Save三者的區別(BatchInsert/BatchReplace/BatchSave同理):
- Insert:使用insert into語句進行資料庫寫入,如果寫入的資料中存在Primary Key或者Unique Key的情況,返回失敗,否則寫入一條新資料;
- Replace:使用replace into語句進行資料庫寫入,如果寫入的資料中存在Primary Key或者Unique Key的情況,刪除原有記錄,按照給定資料新寫入一條新記錄,否則寫入一條新資料;
- Save:使用insert into語句進行資料庫寫入,如果寫入的資料中存在Primary Key或者Unique Key的情況,更新原有資料,否則寫入一條新資料;
鏈式操作
gdb提供簡便靈活的鏈式操作介面,通過資料庫物件的db.Table/db.From方法或者事務對象的tx.Table/tx.From方法基於指定的資料表返回一個鏈式操作對象DbOp,該對象可以執行以下方法(具體方法說明請參考API文檔)。
func LeftJoin(joinTable string, on string) (*DbOp)func RightJoin(joinTable string, on string) (*DbOp)func InnerJoin(joinTable string, on string) (*DbOp)func Fields(fields string) (*DbOp)func Limit(start int, limit int) (*DbOp)func Data(data interface{}) (*DbOp)func Batch(batch int) *DbOpfunc Where(where string, args...interface{}) (*DbOp)func GroupBy(groupby string) (*DbOp)func OrderBy(orderby string) (*DbOp)func Insert() (sql.Result, error)func Replace() (sql.Result, error)func Save() (sql.Result, error)func Update() (sql.Result, error)func Delete() (sql.Result, error)func Select() (List, error)func All() (List, error)func One() (Map, error)func Value() (interface{}, error)
資料庫樣本
https://gitee.com/johng/gf/bl...
方法操作
擷取ORM單例對象
// 擷取預設配置的資料庫物件(配置名稱為"default")db, err := gdb.Instance()// 擷取配置分組名稱為"user-center"的資料庫物件db, err := gdb.Instance("user-center")
資料寫入
r, err := db.Insert("user", gdb.Map { "name": "john",})
資料查詢(列表)
list, err := db.GetAll("select * from user limit 2")
資料查詢(單條)
one, err := db.GetOne("select * from user limit 2")// 或者one, err := db.GetOne("select * from user where uid=1000")
資料儲存
r, err := db.Save("user", gdb.Map { "uid" : 1, "name" : "john",})
大量操作
// BatchInsert/BatchReplace/BatchSave 同理_, err := db.BatchInsert("user", gdb.List { {"name": "john_1"}, {"name": "john_2"}, {"name": "john_3"}, {"name": "john_4"},}, 10)
資料更新/刪除
// db.Update/db.Delete 同理r, err := db.Update("user", gdb.Map {"name": "john"}, "uid=?", 10000)r, err := db.Update("user", "name='john'", "uid=10000")r, err := db.Update("user", "name=?", "uid=?", "john", 10000)
注意,參數域支援並建議使用預先處理模式進行輸入,避免SQL注入風險。
鏈式操作
鏈式查詢
// 查詢多條記錄並使用Limit分頁r, err := db.Table("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*, ud.site").Where("u.uid > ?", 1).Limit(0, 10).Select()// 查詢合格單條記錄(第一條)r, err := db.Table("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*,ud.site").Where("u.uid=?", 1).One()// 查詢欄位值r, err := db.Table("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("ud.site").Where("u.uid=?", 1).Value()// 分組及排序r, err := db.Table("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*,ud.city").GroupBy("city").OrderBy("register_time asc").Select()
鏈式更新/刪除
// 更新r, err := db.Table("user").Data(gdb.Map{"name" : "john2"}).Where("name=?", "john").Update()r, err := db.Table("user").Data("name='john3'").Where("name=?", "john2").Update()// 刪除r, err := db.Table("user").Where("uid=?", 10).Delete()
鏈式寫入/儲存
r, err := db.Table("user").Data(gdb.Map{"name": "john"}).Insert()r, err := db.Table("user").Data(gdb.Map{"uid": 10000, "name": "john"}).Replace()r, err := db.Table("user").Data(gdb.Map{"uid": 10001, "name": "john"}).Save()
鏈式批量寫入
r, err := db.Table("user").Data(gdb.List{ {"name": "john_1"}, {"name": "john_2"}, {"name": "john_3"}, {"name": "john_4"},}).Insert()
可以指定大量操作中分批寫入資料庫的每批次寫入條數數量:
r, err := db.Table("user").Data(gdb.List{ {"name": "john_1"}, {"name": "john_2"}, {"name": "john_3"}, {"name": "john_4"},}).Batch(2).Insert()
鏈式批量儲存
r, err := db.Table("user").Data(gdb.List{ {"uid":10000, "name": "john_1"}, {"uid":10001, "name": "john_2"}, {"uid":10002, "name": "john_3"}, {"uid":10003, "name": "john_4"},}).Save()
事務操作
開啟事務操作可以通過執行db.Begin
方法,該方法返回事務的操作對象,類型為*gdb.Tx
,通過該對象執行後續的資料庫操作,並可通過tx.Commit
提交修改,或者通過tx.Rollback
復原修改。
開啟事務操作
if tx, err := db.Begin(); err == nil { fmt.Println("開啟事務操作")}
事務操作對象可以執行所有db對象的方法,具體請參考API文檔。
交易回復操作
if tx, err := db.Begin(); err == nil { r, err := tx.Save("user", gdb.Map{ "uid" : 1, "name" : "john", }) tx.Rollback() fmt.Println(r, err)}
事務提交操作
if tx, err := db.Begin(); err == nil { r, err := tx.Save("user", gdb.Map{ "uid" : 1, "name" : "john", }) tx.Commit() fmt.Println(r, err)}
事務鏈式操作
事務操作對象仍然可以通過tx.Table
或者tx.From
方法返回一個鏈式操作的對象,該對象與db.Table
或者db.From
方法傳回值相同,只不過資料庫操作在事務上執行,可提交或復原。
if tx, err := db.Begin(); err == nil { r, err := tx.Table("user").Data(gdb.Map{"uid":1, "name": "john_1"}).Save() tx.Commit() fmt.Println(r, err)}
其他鏈式操作請參考上述鏈式操作章節。