文章来源:
gf框架的数据库ORM操作由gdb包提供支持,gdb包经过非常精心优雅的设计,提供了非常强大的配置管理、方法操作、链式操作、事务操作等功能。gdb包具体API说明文档详见: 。本章节对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数据库操作的方法比较多,具体详见,以下仅对一些常用的方法进行介绍。
方法操作
// 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,该对象可以执行以下方法(具体方法说明请参考)。
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)
数据库示例
方法操作
-
获取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对象的方法,具体请参考。
-
事务回滚操作
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)}
其他链式操作请参考上述链式操作章节。