GORM操作实例与ORM思考 | 青训营

246 阅读5分钟

> 前言: 通过文档和课程视频学习到了GORM的一些基础使用和设计思想而做出的总结

什么是GORM?

GORM 官网中对它自己的定义是什么呢 ?

  The fantastic ORM library for Golang aims to be developer friendly.

  这个出色的 Golang ORM 库的目标是为开发者提供友好的体验。

正如官网自述,这确实是一个非常优秀的ORM框架,支持市面上大部分主流数据库,全功能ORM,将Go的数据类型映射到数据库表中去,简化数据库操作,通过将数据库表和记录映射为Go中的对象和属性,实现对象与数据库之间的无缝交互

还有其他Golang语言实现的ORM框架像是Xorm、Gorose等,但这已经不是我们当前讨论的范围里,其实具体思想都相差不多,选一个主流的来学习就行。

讨论GORM之前,我想对比在另外一门很热门的后端语言Java的ORM框架 Mybatis,其实原生Mybatis的ORM性还是比较弱,不能直接实现简单CRUD,还是需要在Xml提前定义查询SQL,通过动态代理的形式去执行,虽然有较高的灵活性但是无论何种业务都需要手动填充SQl。 (MybatisPlus不在讨论范围中

而GORM提供链式调用API,体验较好,复合多表实现简单,数据库结构迁移也很方便,灵活的可扩展插件 API,这些是原生Mybatis不具有的功能,跨语言比较意义不太大只是类比于自己熟悉的语言学习起来比较方便

GORM基本操作

连接数据库

通过数据库DSN(数据源名称,Datasource Name),描述数据库连接一般像下面这样 👇

[username[:password]@][protocol[(address)]]/database[?param1=value1&...&paramN=valueN]

    //配置MySQL连接参数
    username := "root"   //账号
    password := "root" //密码
    host := "localhost"  //数据库地址,可以是Ip或者域名
    port := 3306         //数据库端口
    Dbname := "myDatabase"  //数据库名
    timeout := "10s"     //连接超时,10秒


    //拼接Dsn 参数
    dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local&timeout=%s",
    username, password,
    host, port,
    Dbname, timeout)

    //连接Mysql, 获得DB类型实例,用于后面的数据库读写操作。
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        panic(err)
    }

通过获取gorm.DB对象就完成了对数据库的连接,GORM内部也对连接进行了池化复用,有兴趣可以深入了解

插入数据

获取到Gorm的DB对象后就可以对其进行操作

    u := &User{
        Name: "Peter",
        Age:  1,
    }
    res := DB.Create(u)
    log.Printf("%v", res.Error)        // 返回 error
    log.Printf("%v", res.RowsAffected) // 返回插入记录的条数
    log.Printf("%v", u.ID)             // 返回插入数据的主键

DB.Create 传入一个结构体指针在插入结束后将主键返回写回ID中去,插入数据还有很多很详细的操作,这里就不一一介绍了可以查询GORM文档 👉 GORM

查询数据

数据库中数据查询也是非常重要的,GORM也提供了非常方便的查询接口

查询一条记录

GORM 提供了 FirstTakeLast 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件,部分情况下只有一条记录,就需要这种只返回一条数据的查询方法

    u = &User{}
    DB.Last(u)  // 最后一条数据 以主键为排序规则
    DB.First(u) // 第一条数据 以主键为排序规则
    DB.Take(u)  //直接 Limit 1 无序规则

查询所有记录

直接指明Find就能查询 DB.Find(&users)

条件查询

条件查询才是用的最多的查询,那么如何在GORM中使用条件查询呢,可以链式调用Where方法或者Find方法,在其中通过占位符 ? 进行参数的绑定,还可以通过结构体进行参数绑定,但是会忽略结构体字段的空值,Number类型的0或0.0f或是string 的 "" 这也是一个有点小坑的地方

//  Struct Query
//  SELECT * FROM users WHERE name = "Alice";
var users []User
DB.Where(&User{Name: "Alice", Age: 0}).Find(&users)

更多更详细的可以查询文档 -> 条件查询

更新和删除数据

更新和删除我感觉相差不大,指定好对应的条件关系就行,更新来说与查询的关系更为密切一些,都可指定钩子函数,在执行sql语句之前进行回调操作 -> 更新

GORM-Gen

更友好 & 更安全 GORM 代码生成。

虽然Gorm提供的全功能ORM体验很好,但是缺少一些类型检查功能,字段指定都是通过字面量去实现的,错误发生也比较隐含,不容易被发现而GORM-Gen通过代码生成的方式进行静态代理实现类型检查,约束查询字段,但是依然不缺少GORM的全部功能,提供更加友好的编程体验,篇幅有限这里就不详细的说明了 Gen Guides

总结

总体而言 GORM是一个很优秀的ORM框架,也通过一些代码生成的方式强化了类型约束,我也比较推荐通过代码生成的方式去编写数据操作代码,GORM还有很多的特性没有介绍,事务和数据库迁移等等特性都没有介绍,Gorm官方也支持Otel的可观测性接入,社区也很活跃,我也会继继续深入学习的 ヾ(≧▽≦*)o