驱动引入

为了将数据库驱动与框架主库解耦,从v2.1版本开始,所有的数据库驱动都需要通过社区包手动引入。

数据库驱动的安装和引入请参考:https://github.com/gogf/gf/tree/master/contrib/drivers

基本介绍

GoFrame框架的ORM功能由gdb模块实现,用于常用关系型数据库的ORM操作。

gdb数据库引擎底层采用了链接池设计,当链接不再使用时会自动关闭,因此链接对象不用的时候不需要显式使用Close方法关闭数据库连接。

注意:为提高数据库操作安全性,在ORM操作中不建议直接将参数拼接成SQL字符串执行,建议使用预处理的方式(充分使用?占位符)来传递SQL参数。gdb的底层实现中均采用的是预处理的方式处理开发者传递的参数,以充分保证数据库操作安全性。

接口文档:

https://pkg.go.dev/github.com/gogf/gf/v2/database/gdb

组件特性

GoFrame ORM组件具有以下显著特点: 

  1. 全自动化支持嵌套事务。
  2. 面向接口化设计、易使用易扩展。
  3. 内置支持主流数据库类型驱动,并易于扩展。
  4. 强大的配置管理,使用框架统一的配置组件。
  5. 支持单例模式获取配置同一分组数据库对象。
  6. 支持原生SQL方法操作、ORM链式操作两种方式。
  7. 支持OpenTelemetry可观测性:链路跟踪、日志记录、指标上报。
  8. 通过Scan方法自动识别Map/Struct接收查询结果,自动化查询结果初始化、结构体类型转换。
  9. 通过返回结果nil识别为空,无需sql.ErrNoRows识别查询数据为空的情况。
  10. 全自动化的结构体属性-字段映射,无需显示定义结构体标签维护属性-字段映射关系。
  11. 自动化的给定Map/Struct/Slice参数类型中的字段识别、过滤,大大提高查询条件输入、结果接收。
  12. 完美支持GoFrame框架层面的DAO设计,全自动化Model/DAO代码生成,极大提高开发效率。
  13. 支持调试模式、日志输出、DryRun、自定义Handler、自动类型类型转换、自定义接口转换等等高级特性。
  14. 支持查询缓存、软删除、自动化时间更新、模型关联、数据库集群配置(软件主从模式)等等实用特性。

知识图谱

GoFrame ORM Features

组件关联

GoFrame ORM Dependencies

g.DBgdb.Newgdb.Instance

获取数据库操作对象有三种方式,一种是使用g.DB方法(推荐),一种是使用原生gdb.New方法,还有一种是使用包原生单例方法gdb.Instance,而第一种是推荐的使用方式。这三种方式的区别如下:

  1. g.DB对象管理方式获取的是单例对象,整合了配置文件的管理功能,支持配置文件热更新。
  2. gdb.New是根据给定的数据库节点配置创建一个新的数据库对象(非单例),无法使用配置文件。
  3. gdb.Instance是包原生单例管理方法,需要结合配置方法一起使用,通过分组名称(非必需)获取对应配置的数据库单例对象。

有这么多对象获取方式原因在于GoFrame是一个模块化设计的框架,每个模块皆可单独使用。

New创建数据库对象

db, err := gdb.New(gdb.ConfigNode{
	Link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test",
})

获取数据库对象单例

// 获取默认配置的数据库对象(配置名称为"default")
db := g.DB()

// 获取配置分组名称为"user"的数据库对象
db := g.DB("user")


// 使用原生单例管理方法获取数据库对象单例
db, err := gdb.Instance()
db, err := gdb.Instance("user")

相关文档




Content Menu

  • No labels

58 Comments

  1. 请问orm报错empty database configuration for item name 'default'是什么问题呀,之前一直没有问题,这两天就不行了。但是数据库配置也没问题,在test包测试执行同样的orm也没问题(但是我重新装过go,不知道有没有关系)。执行gf gen dao也是报错Error: database initialization failed

    1. 表示你的配置文件中的数据库配置有问题,检查一下,参考一下:ORM使用配置

  2. 在微服务生产环境中,通常有数据库 migrate 需求,这块 ORM 是否有考虑支持?

    1. 暂无考虑。

      1. 那么项目中遇到随着版本更新,数据库的变更,比如2.0 比1.0 新增字段,新增表;需要进行版本升级,保留1.0的数据; 该怎么做呢?

  3. gdb 有类似gormAutoMigrate 自动建表功能吗?最近在学习focus发现用的是gdb但是搜了下没发现自动建表的功能 需要手动建表或者导入 是我没搜到还是没有呢?

    1. goframeorm没有migrate功能,未来估计也不太可能会有。

      1. ssz

        发现两个问题

        1、很多团队是基于 模型驱动开发(DDD),尤其是Java团队转过来的人群,建议支持 AutoMigrate

        2、支持手动关闭数据库连接,比如在一些嵌入式设备上,需要多个进程修改sqlite中的数据,不能手动关闭,很容易造成database locked 

        1. ssz

          当然,可能会有人建议我去用gormxorm 但是还是希望国产框架能够做的更好哈

        2. GoFrame ORM不支持Migrate特性,这种特性不太严谨,未来应该也不太可能会支持。你另外一个关于数据库连接关闭的问题,是可以手动关闭的,建议可以结合文档和源码一起看看。

    2. DDL操作 和 DML操作应该分开

      代码 应该只操作数据   而不应该操作数据库表

      权限越位了。

      且库表的创建修改权限,应该集中在技术管理人员手里,如果放在代码账号里,

      人人都有权限,存在操作风险哦,团队内的成员,SQL水平参差不齐,安全意识也不一定到位。


      1. ssz

        这是管理上的问题,不是所有问题都要在开发层面解决

  4. postgresql 如何支持LastInsertId,有别的方法可以用吗

    1. postgresql 如何实现获取自增主键

    2. gorm Create 是会返回主键的,请问,gform如何返回postgresql主键 RETURNING "id"

        1. hyh

          django 中的实现: https://github.com/django/django/blob/main/django/db/backends/postgresql/operations.py

          "github.com/lib/pq"

          用户是否可以在 insert sql 后面自己加 RETURNING "id"

          1. 很简单,可以提个PR。

  5. xx

    请问g.DB().GetStructs这些使用sql语句查询的api怎么调Cache函数做数据缓存?

    1. 你可以看看Raw方法通过SQL语句创建为Model,随后可以使用Model的数据缓存特性。

  6. ORM开启多链接的情况下,有没计划提供针对同一对象的操作顺序保障。

    因为在多连接情况下同一对象的操作请求走不同链接可能会导致数据的最终结果和预期的不一致。

    1. 多连接情况下同一对象的操作请求走不同链接可能会导致数据的最终结果和预期的不一致。

      你这个场景或许只有事务能帮助你,可以参考下章节:ORM事务处理

  7. 请问 orm 可以支持 hooks 操作吗?这样清理缓存就可以方便很多,且同一个 model 对应的多个缓存也可以一并清理

    如:

    _, err := db.Table("user").Cache(-1, "vip-user").Data(gdb.Map{"name": "smith"}).Where("uid", 1).Update()

    就可以改造为:

    _, err := db.Table("user").Data(gdb.Map{"name": "smith"}).Where("uid", 1).Update()
    
    func afterSave(instance) {
    	g.Redis().Do("del", "vip-user")
    	g.Redis().Do("del", <其他 key>) 
    
    }
    1. GoFrame ORM支持数据库级别的回调处理,具体请参考章节:ORM接口开发-回调处理 目前暂不支持Model级别的回调功能。

  8. 在调试中除了使用日志功能输出原生SQL语句的方法,还有没有链式操作的方法API输出原生的SQL语句?我在调试过程中,发现update无法输出原生SQL语句

    1. 请自己检查程序逻辑。

  9. xx

    大佬,请问mongodb这个应该这么用呢?网上找了也没看到goframe有人用过

      1. xx

        这个我也看到了,官方这个据说不太好用。主要是怎么优雅的结合gf一起使用

      2. 七牛封装了一个

  10. g

    ORM似乎不支持postgresql的数组类型,数据库中 是float4数组,通过orm查询出来的数据返回 “0”

    1. 请提个issue,把具体的类型名称发一下

  11. 请问一下,这个orm是否支持事件监听

  12. 请问有没有类似beforeSave() , afterSave() 这样类似的方法,或者说类似的功能该怎么实现

    1. GoFrame的ORM采用的是接口化设计,没有HOOK功能,你可以使用接口覆盖来实现自定义功能,相比较HOOK设计灵活性和扩展性更高。请参考:ORM接口开发-回调处理

  13. 强哥,看到深入有点晕,在控制器里查询数据是直接用g.model("user") 还是用dao.User,包括在service里面, 什么时候用g.model("user") 和 dao.user 还是很模糊,这两者有什么区别呢

  14. 在控制器里查询数据是直接用g.model("user") 还是用dao.User,包括在service里面, 什么时候用g.model("user") 和 dao.user 还是很模糊,这两者有什么区别呢  我看着也蒙,这两种有各自的应用场景吗?

    1. dao是项目工程管理中的模块,由框架工具自动生成和维护,推荐开发业务项目都按照框架推荐的工程结构进行。

      g.Model是便捷的模型创建方法,相对上层业务的工程架构来讲,是属于较低层的组件工具方法。

  15. 你好,请问一下,这个orm能实现监听binlog吗?

    1. 你好,个人觉得这并不是ORM应该做的事情。

  16. _, e := dao.User.Ctx(ctx).Insert(&u)
    这个怎么获取mysql的错误码呢?这样出错
    mysqlErr, ok := e.Error.(mysql.MySQLError)
    if ok {
    if mysqlErr.Number == 1062 {
    // solve the duplicate key error.
    //return error("")

    }
    }
    1. 获取error的错误码可以使用gerror.Code方法,具体请参考章节:错误处理-错误码使用


  17. 郭强 ,  driver分离后,做单元测试时,如何处理, 是否得在每个会调用orm的test.go文件,都要手动引入 

    _ "github.com/gogf/gf/contrib/drivers/mysql/v2"
    1. 我是这个样子,

    2. lance 强仔 在相同包下只需要引用一次即可。

  18. 有这么多对象获取方式原因在于GoFrame是一个模块化设计的框架,每个模块皆可单独使用。

    -------------

    之前不理解, 现在知道了, 我就说咋就创建对象都这么多方法. 

  19. 目前的ORM中是否可以实现跨进程的事务处理?

    gtrace.SetBaggageValue(ctx, "tx", tx)

    在另一个服务中用GetBaggageValue实际上是拿不到的,是否可以把Tx的 TranslationId返回,另一个进程中通过TranslationId构造这个gdb.TX

    -----------------------------

    另外:跨进程的事务的设计是否合理?是否应该避免?

    1. 事务, 应该是数据库本身提供的功能, 和进程与否没有关系. 

      换言之,  --->可以实现跨进程的事务处理

    2. 这不就是分布式事务的基础原型吗

  20. 不支持AutoMigrate 的话,涉及分表该怎么做呢?

    例如,类似金融里的行情数据,如果所有标的的tick行情数据都保存到一个表里面,这个表就会特别大而且查询速度会特别慢,通常的做法就是根据标的来分表,每个标的单独一个表。这些表的结构都一样,但是表名不一样。

    每当有新的标的出现时,就得动态创建一个单独的表。这种情况只能用原生SQL或者直接使用类似gorm的包么?

    1. 可以用hook特性去实现,但目前在hook中替换in.Table还不能生效需要等待修复这个问题.临时可以用repace去实现或者直接fork自己改

      1. 好的 谢谢,我试试

  21. 用gf gen dao生成的代码经常会报这个错误

    internal/dao/internal/ibk_info.go:80:39: cannot use f (variable of type func(ctx context.Context, tx *gdb.TX) error) as type func(ctx context.Context, tx gdb.TX) error in argument to dao.Ctx(ctx).Transaction

    1. 更新下对应版本的cli

      1. 好的 gf up -a

  22. 因业务需要,对于分表有极大的需求,不知道这个db能介入go-gorm sharding吗?或者说可以通过什么方法,最终实现分表。谢谢大佬们。

  23. 佬!gf orm 有类似gorm数据库迁移的功能吗,翻了翻文档没找到。