Go中主流的ORM框架优劣势对比发布于 2个月前442 热度0 评论轻雨伞下0 粉丝 36 篇博客关注打赏

Go中主流的ORM框架优劣势对比发布于 2个月前442 热度0 评论轻雨伞下0 粉丝 36 篇博客关注打赏

一、引言

简单说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写。在Go中,ORM可以把数据库里的表格映射成 Go 语言中的结构体,然后你只需要像操作对象那样去增删改查数据,而不必烦恼那些冗长的 SQL 语句,同时很多 ORM 框架都支持多种数据库,切换底层数据库时只需要做简单配置。但受限于Go本身的语法,目前主流的ORM,大部分都非常的难用,萝卜青菜各有所爱,本系列为大家介绍一些主流的Go ORM,供大家对比选择。

二、常见ORM

在v站的一篇帖子下,我收集了回帖中提到比较多的ORM,并根据内部实现机制和设计理念,将Go ORM 框架分成了三类

🌲 反射型主要通过反射机制将结构体映射到数据库表上,代表作为 go-gorm/gorm

🌲 代码生成型通过代码生成工具预先生成数据模型及查询构建器,代表作有 ent/ent 和日益流行的 go-gorm/gen

🌲 SQL 增强型基于原生 SQL 库进行封装和扩展,既保留 SQL 的灵活性,又提供了一系列便捷函数,代表作为 jmoiron/sqlx

实现方式

Go ORM库

star

reflect to struct

go-gorm/gorm

36.6k

reflect to struct

go-xorm/xorm

6.7k

reflect to struct

upper/db

3.5k

Code gen

go-gorm/gen

2.3k

Code gen

ent/ent

15.9k

Code gen

sqlc-dev/sqlc

14.2k

SQL enhance

Masterminds/squirrel

7.1k

SQL enhance

jmoiron/sqlx

16.6k

1、反射型

反射型 ORM 利用 Go 语言的反射机制,在运行时将结构体的字段和标签动态映射到数据库表中,自动生成 SQL 语句来实现 CRUD 操作。这种方式无需预先生成代码,使用较为简单直观。

优势:

开发简便:直接基于结构体定义进行数据库操作,无需额外生成代码

动态灵活:自动识别结构体字段和标签,支持自动迁移和关联查询

缺点:

性能开销:反射机制会引入运行时开销,在高并发场景下可能成为瓶颈

类型安全不足:导致部分类型错误依赖运行时检查,无法在编译期捕获

go-gorm/gorm 是目前最流行的反射型 ORM 框架,甚至可以说是Go中最流行的ORM 框架

个人感受,受限Go语法加上作者的设计思路,导致gorm过度依赖 interface{},各种隐式规则,使用时相当不方便,有一种让Go退化成了弱类型的感觉,不仅没有办法做到字段提示,每次传参都得看文档。

其示例代码如下:

package main

import (

"log"

"gorm.io/driver/sqlite"

"gorm.io/gorm"

)

type User struct {

gorm.Model

Name string`gorm:"not null"`

Email string`gorm:"unique;not null"`

}

func main() {

db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{})

if err != nil {

log.Fatal(err)

}

// 堆代码 duidaima.com

// 创建记录

db.Create(&User{Name: "Alice", Email: "alice@example.com"})

// 查询记录

var user User

db.First(&user, "name = ?", "Alice")

log.Printf("User: %+v\n", user)

}

2、代码生成型

因为Go语法限制,反射实现注定没有办法做到类型安全,因此催生出了代码生成这个流派。代码生成型 ORM 框架通过解析开发者定义的 schema,然后生成类型安全的代码文件,这种方式能在编译时捕获类型错误,同时避免运行时反射带来的性能损耗,虽然使用前需要执行代码生成步骤,但在大型项目中,这种方式能提供更高的安全性和性能。

优势:

编译期类型检查:生成的代码可以在编译时捕获错误。

高运行时性能:无需依赖反射,运行时效率更高。

缺点:

额外生成步骤:需要预先运行代码生成命令,增加构建流程。

开发流程复杂:生成代码与手写代码之间的同步和维护可能增加开发难度,尤其在频繁修改 schema 时。

go-gorm/gen 是与 GORM 配套的代码生成工具,是代码生成型ORM的后起之秀,为 GORM 提供了更强的类型安全查询接口,提升了性能和编译时检查能力。ent/ent 是目前代码生成型ORM中最流行的,个人相对比较喜欢,虽然跟Rust或者TS的ORM相比体验还是差很多, 哎,没办法啊。Ent需要开发者先定义 schema,然后通过命令行工具生成代码。生成的代码包含了模型、查询构建器和数据库迁移工具,从而确保数据库操作的类型安全和高效性。

以下示例忽略了schema和代码生成部分

package main

import (

"context"

"log"

"entgo.io/ent/dialect/sql"

_ "github.com/mattn/go-sqlite3"

"entgo.io/ent/examples/start/ent"

)

func main() {

client, err := ent.Open(sqlite.Open("./ent.db"), &sql.Config{Driver: "sqlite3"})

if err != nil {

log.Fatal("failed to connect to the database:", err)

}

defer client.Close()

// 创建一个新用户

user, err := client.User.Create().

SetName("Alice").

SetEmail("alice@example.com").

Save(context.Background())

if err != nil {

log.Fatal(err)

}

log.Println("User created:", user)

}

3、SQL增强型库

有一部分人认为ORM是一个鸡肋的概念,尤其在Go中,因此选择裸写SQL的方式。SQL增强型库在原生 SQL 库的基础上进行扩展,不隐藏 SQL 语句,而是通过提供额外的封装函数和数据映射机制,帮助开发者更高效地执行查询和数据转换。它保持了 SQL 的灵活性,同时简化了常见操作。

优势:

灵活性高:保留 SQL 语句的编写自由,适合复杂查询

数据映射简化:自动绑定查询结果到结构体,减少手动转换代码

轻量高效:直接使用原生 SQL,无额外 ORM 开销

缺点:

需要手写 SQL:开发者必须自行编写 SQL,可能会增加样板代码和维护难度

缺少高级抽象:没有 ORM 提供的自动关联、迁移和数据验证功能

jmoiron/sqlx 是一款流行的 SQL 增强型库,其示例代码如下:

package main

import (

"log"

"github.com/jmoiron/sqlx"

_ "github.com/mattn/go-sqlite3"

)

type User struct {

ID int `db:"id"`

Name string`db:"name"`

Email string`db:"email"`

}

func main() {

db, err := sqlx.Connect("sqlite3", "sqlx.db")

if err != nil {

log.Fatal(err)

}

// 查询数据

var user User

err = db.Get(&user, "SELECT * FROM users WHERE id=?", id)

if err != nil {

log.Fatal(err)

}

log.Printf("User: %+v\n", user)

}

三、总结

总结下:Go ORM 框架各有优势与不足:

1.反射型(如 GORM)开发简单、上手快,但反射带来的性能开销和语法缺陷,导致用起来很别扭,但好在GORM应用广泛,网上的资料和文档也比较多

2.代码生成型(如 Ent、go-gorm/gen)通过生成类型安全的代码提供了更高的性能和编译时检查,但需要额外的代码生成步骤,开发流程相对复杂

3.SQL增强型库(如 sqlx)在保留 SQL 灵活性的同时,通过扩展封装提升了开发效率,非常适合不喜欢ORM概念的开发者

总之,受限Go语法目前没有特别好用的ORM库,大家只能根据个人喜欢和流行程度来自行选择了。

相关文章

奥拉星大电影购票攻略(淘宝)
365bet体育在线下载

奥拉星大电影购票攻略(淘宝)

📅 07-12 👁️ 6583
手机时间怎么修改
365bet官网平台网址

手机时间怎么修改

📅 07-11 👁️ 3935
充电宝多少钱一个?2023最新价格及选购指南
365bet怎么提款

充电宝多少钱一个?2023最新价格及选购指南

📅 06-29 👁️ 9774
火锅热量高吗 一顿火锅要运动多久
365bet体育在线下载

火锅热量高吗 一顿火锅要运动多久

📅 07-04 👁️ 2099
lol各种标记操作 LOL如何正确使用标记
365bet官网平台网址

lol各种标记操作 LOL如何正确使用标记

📅 07-07 👁️ 1808
面包机总排行榜
365bet体育在线下载

面包机总排行榜

📅 06-28 👁️ 5485