资讯专栏INFORMATION COLUMN

gf框架之gdb - 优雅强大的数据库ORM

muzhuyu / 1984人阅读

摘要:文章来源框架的数据库操作由包提供支持,包经过非常精心优雅的设计,提供了非常强大的配置管理方法操作链式操作事务操作等功能。其他链式操作请参考上述链式操作章节。

文章来源:http://gf.johng.cn/494380

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) *DbOp

func 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)
}

其他链式操作请参考上述链式操作章节。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/38979.html

相关文章

  • gf框架gdb - 优雅强大据库ORM

    摘要:文章来源框架的数据库操作由包提供支持,包经过非常精心优雅的设计,提供了非常强大的配置管理方法操作链式操作事务操作等功能。其他链式操作请参考上述链式操作章节。 文章来源:http://gf.johng.cn/494380 gf框架的数据库ORM操作由gdb包提供支持,gdb包经过非常精心优雅的设计,提供了非常强大的配置管理、方法操作、链式操作、事务操作等功能。gdb包具体API说明文档详...

    silenceboy 评论0 收藏0
  • 如何优雅写一篇安利文-以Sugar ORM为例

    摘要:前言我最近喜欢把写的十分优美的技术文章叫做安利文。优雅带有很强烈的资产阶级文艺小资派气息,要习惯装的像个文青,大胆优雅的去写安利文。如果让你有了第二天自己写一篇安利文的冲动,也算这篇文章没有白写。 前言 我最近喜欢把写的十分优美的技术文章叫做安利文。首先,文章必须是原创而非软广;其次,阅读之后不仅能快速吸纳技术要点并入门开发,还能感同身受的体会作者热情洋溢的赞美和急于分享心得体验的心情...

    shevy 评论0 收藏0
  • 轻量级 PHP 框架 TinyLara 更新:更优雅 附中文介绍

    摘要:中文介绍是一个轻量级框架,基于,可以看成的精简版。官方网站项目地址开始使用下载或者安装依赖包修改数据库配置文件,将导入数据库。一行代码即可发送邮件。协议采用协议分发,衍生项目除了必须采用协议之外无任何限制。 TinyLara showImg(http://lvwenhan.com/content/uploadfile/201410/dcd81414652600.png); __...

    loonggg 评论0 收藏0
  • golang ormgorose 2.0版本正式发布

    摘要:关于最风骚的版本的经过几个月的重构和打磨再加上近一个月的预览版测试和改进正式版终于与我们见面了新版本做出了重大改动和升级完全重构了基础架构和实现方式下面我们一起来看看的特点吧特点全新架构采用模块化分离架构主要分为大模块初始化和数据库链接配置 关于gorose 2.0 gorose, 最风骚的golang orm, php版本的laravel eloquent. 经过几个月的重构和打磨...

    android_c 评论0 收藏0
  • 手把手教你在Flutter项目优雅使用ORM据库

    摘要:等常用的数据类型。就是这个模型的名字,之后我们为索引使用这个数据模型。结语目前领域最大的痛点就是数据库操作,本文提供了一种优雅使用数据库的方法,大幅降低了使用数据库的门槛。 Flutter ORM数据库介绍 Flutter现在开发上最大的槽点可能就是数据库使用了,Flutter现在只提供了sqflite插件,这表明开发者手动写sql代码,建表、建索引、transation、db线程控制...

    zlyBear 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<