基本介绍

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

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

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

接口文档:

https://godoc.org/github.com/gogf/gf/database/gdb

接口关系:

GoFrame ORM Relations

知识图谱

GoFrame ORM Features

组件关联

GoFrame ORM Dependencies

数据结构

为便于数据表记录的操作,ORM定义了5种基本的数据类型:

type Map         map[string]interface{} // 数据记录
type List        []Map                  // 数据记录列表

type Value       *gvar.Var              // 返回数据表记录值
type Record      map[string]Value       // 返回数据表记录键值对
type Result      []Record               // 返回数据表记录列表
  1. MapList用于ORM操作过程中的输入参数类型(与全局类型g.Mapg.List一致,在项目开发中常用g.Mapg.List替换)。
  2. Value/Record/Result用于ORM操作的结果数据类型,具体说明请查看 ORM结果处理 章节。

g.DBgdb.Newgdb.Instance

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

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

有这么多对象获取方式原因在于GoFrame是一个模块化设计的框架,每个模块皆可单独使用。为了方便开发者使用常用的一些模块,因此框架也提供了一个g模块,这是一个高度耦合的模块,封装了一些常用对象的单例获取方式,详见 对象管理 章节。

获取ORM对象示例:

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

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

// 使用原生New方法创建数据库对象
db, err := gdb.New()
db, err := gdb.New("user-center")

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

// 注意不用的时候不需要使用Close方法关闭数据库连接(并且gdb也没有提供Close方法),
// 数据库引擎底层采用了链接池设计,当链接不再使用时会自动关闭

支持的数据库类型

由于go标准库的数据库操作对象采用接口实现,因此提供了非常好的可扩展性和兼容性。

MySQL

内置支持,无需额外扩展或第三方包接入,直接可用。 依赖的第三方包:https://github.com/go-sql-driver/mysql

SQLite

在使用时需要引入第三方包 ( go-sqlite3 ):

_ "github.com/mattn/go-sqlite3"
  1. 不支持Save/Replace方法

PostgreSQL

在使用时需要引入第三方包 (pq ):

_ "github.com/lib/pq"
  1. 不支持LastInsertId方法
  2. 不支持Save/Replace方法

SQL Server

使用时需导入第三方包 (go-mssqldb ):

_ "github.com/denisenkom/go-mssqldb"
  1. 不支持LastInsertId方法
  2. 不支持Save/Replace方法
  3. 仅支持SQL Server 2005及其后的版本

Oracle

使用时需导入第三方包 (go-oci8 ):

_ "github.com/mattn/go-oci8"
  1. 不支持LastInsertId方法
  2. 不支持Save/Replace方法

其他数据库类型

额外接入新的数据库相当方便,可参考源码中关于PostgreSQLSQLiteOracleSQL Server的接入方式。具体介绍请参考后续 ORM接口开发-驱动开发 章节。






Content Menu

  • No labels

29 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. 这个建议未来还是加上吧

  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. 我有个疑问,支持模型关联吗?我看很多ORM都支持模型关联 写业务便捷些

  10. ORM关于分页的相关介绍在文档的什么位置呢?

  11. 新手, 请求一下 dao 生成我是要先定义数据库表结构吗?