Gorm 入门介绍与基本使用
目录
一、ORM简介
1.1 什么是ORM
ORM(Object-Relational Mapping)是一种编程技术,它将对象和关系数据库之间的映射抽象出来,使得开发者可以通过面向对象的方式操作数据库,而不用直接处理SQL语句,相当于在业务逻辑层和数据库层之间一座桥梁。在Golang中,有一款优秀的ORM框架叫做Gorm,它提供了强大的功能,使得数据库操作变得更加简单和灵活。
1.2 使用ORM的好处
使用ORM的好处主要包括:
1.2.1 避免直接操作SQL语句
ORM框架可以屏蔽底层数据库的细节,开发者不需要编写复杂的SQL语句,从而降低了开发的难度。
1.2.2 提高代码的可维护性
通过使用ORM,代码变得更加清晰、简洁,易于理解和维护。ORM框架通常提供了模型定义、数据验证等功能,使得开发者可以更专注于业务逻辑。
1.2.3 跨数据库兼容性
ORM框架通常提供了对多种数据库的支持,开发者可以轻松切换数据库而无需修改大量代码。
1.3 使用ORM的缺点
使用ORM也有一些缺点,主要包括:
1.3.1 学习成本
学习使用ORM框架需要一定的时间,尤其是对于初学者来说,需要掌握框架的各种功能和用法。
1.3.2 性能开销
ORM框架可能引入一些性能开销,尤其是在处理大量数据时。开发者需要在性能和开发效率之间做出权衡。
1.4 ORM解析过程
ORM框架的解析过程包括以下步骤:
1.4.1 模型定义
开发者需要定义数据模型,通常是一个结构体,表示数据库中的表结构。
1.4.2 数据验证
ORM框架通常提供了数据验证的功能,确保数据的合法性和完整性。
1.4.3 映射关系
ORM框架会建立数据模型与数据库表之间的映射关系,将结构体的字段与表的列进行对应。
1.4.4 CRUD操作
开发者可以通过ORM框架进行CRUD(Create、Read、Update、Delete)操作,而不用直接编写SQL语句。
1.4.5 SQL生成与执行
最终,ORM框架会根据开发者的操作生成相应的SQL语句,并执行在数据库中。
通过以上步骤,开发者可以使用ORM框架方便地进行数据库操作,提高开发效率。
在接下来的部分,我们将深入学习Gorm框架的使用,从入门到精通。
二、Gorm 介绍与安装
2.1 介绍
Gorm是一款用于Golang的ORM框架,它提供了丰富的功能,包括模型定义、数据验证、关联查询等。Gorm的设计目标是简洁而强大,使得开发者能够更轻松地进行数据库操作。
一些Gorm的特性包括:
- 模型定义和操作:
- 全功能 ORM
- 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
- Create,Save,Update,Delete,Find 中的钩子方法
- 支持 Preload、Joins 的预加载
- 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
- 复合主键,索引,约束
- 事务处理和数据库操作:
- 事务,嵌套事务,Save Point,Rollback To Saved Point
- Context、预编译模式、DryRun 模式
- SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
- Auto Migration
- 其他功能:
- 自定义 Logger
- 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
- 每个特性都经过了测试的重重考验
- 开发者友好
最新版本2.x,比1.x有较大改动,注意:Gorm最新地址为https://github.com/go-gorm/gorm,之前https://github.com/jinzhu/gorm地址为v1旧版本
2.2 相关文档
2.3 安装
要使用Gorm,首先需要安装它。可以使用Go的包管理工具go get进行安装:- # 安装gorm
- go get -u gorm.io/gorm
- # 如果要使用`mysql`, `GORM` 做了二次 封装,安装对应数据库的驱动
- go get -u gorm.io/driver/mysql
复制代码 安装完成后,可以在项目中引入Gorm:接下来,我们将学习如何连接数据库并开始使用Gorm。
三、Gorm 连接数据库
3.1 快速连接 MySQL
连接MySQL数据库是Gorm的常见用法。以下是一个简单的例子:- package main
- import (
- "gorm.io/driver/mysql"
- "gorm.io/gorm"
- )
- type Product struct {
- gorm.Model
- Code string
- Price uint
- }
- func main() {
- dsn := "root:123456@tcp(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=True&loc=Local"
- db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
- if err != nil {
- panic("failed to connect database")
- }
- // 迁移 schema
- db.AutoMigrate(&Product{})
- // Create
- db.Create(&Product{Code: "D42", Price: 100})
- // Read
- var product Product
- db.First(&product, 1) // 根据整型主键查找
- db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录
- // Update - 将 product 的 price 更新为 200
- db.Model(&product).Update("Price", 200)
- // Update - 更新多个字段
- db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // 仅更新非零值字段
- db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
- // Delete - 删除 product
- db.Delete(&product, 1)
- }
复制代码 请注意替换username、password和dbname为你自己的数据库信息。这里使用了MySQL数据库,你也可以根据需要选择其他数据库。
3.2 MySQL数据库配置解析
- dsn := "username:password@tcp(localhost:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
复制代码 上述连接字符串(DSN)中的参数有:
- username:password:数据库用户名和密码。
- tcp(localhost:3306):数据库地址和端口。
- /dbname:数据库名称。
- charset=utf8mb4:设置字符集为UTF-8。
- parseTime=True:启用时间解析。
- loc=Local:设置时区。
你可以根据实际情况调整这些参数。
3.3 自定义 MySQL 驱动
GORM 允许通过 DriverName 选项自定义 MySQL 驱动,例如:- package main
- import (
- _ "example.com/my_mysql_driver"
- "gorm.io/driver/mysql"
- "gorm.io/gorm"
- )
- func main() {
- db, err := gorm.Open(mysql.New(mysql.Config{
- DriverName: "my_mysql_driver",
- DSN: "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local", // data source name, 详情参考:https://github.com/go-sql-driver/mysql#dsn-data-source-name
- }), &gorm.Config{})
- }
复制代码 3.4 现有的数据库连接mysql
GORM 允许通过一个现有的数据库连接来初始化 *gorm.DB- import (
- "database/sql"
- "gorm.io/driver/mysql"
- "gorm.io/gorm"
- )
- func main() {
- sqlDB, err := sql.Open("mysql", "mydb_dsn")
- gormDB, err := gorm.Open(mysql.New(mysql.Config{
- Conn: sqlDB,
- }), &gorm.Config{})
- }
复制代码 3.5 切换数据库驱动
Gorm支持多种数据库,你可以根据需要选择不同的数据库驱动。上面的例子中我们使用了MySQL的驱动,如果要连接其他数据库,只需更改导入的数据库驱动即可。
例如,如果要连接SQLite数据库,可以使用以下驱动:- import "gorm.io/driver/sqlite"
复制代码 然后在gorm.Open()中使用sqlite.Open()。
3.6 编写新驱动
GORM 官方支持的数据库类型有:MySQL, PostgreSQL, SQLite, SQL Server 和 TiDB
有些数据库可能兼容 mysql、postgres 的方言,在这种情况下,你可以直接使用这些数据库的方言。
对于其它不兼容的情况,您可以自行编写一个新驱动,这需要实现 方言接口。
参考官网文档:【编写新驱动】
3.7 连接PostgreSQL
3.7.1 连接PostgreSQ举例
- package main
- import (
- "gorm.io/driver/postgres"
- "gorm.io/gorm"
- )
- type User struct {
- gorm.Model
- Name string
- Age int
- }
- func main() {
- dsn := "host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai"
- db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
- if err != nil {
- panic("failed to connect database")
- }
- defer db.DB()
- // Migrate the schema
- db.AutoMigrate(&User{})
- }
复制代码 我们使用 pgx 作为 postgres 的 database/sql 驱动,默认情况下,它会启用 prepared statement 缓存,你可以这样禁用它:- // https://github.com/go-gorm/postgres
- db, err := gorm.Open(postgres.New(postgres.Config{
- DSN: "user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai",
- PreferSimpleProtocol: true, // disables implicit prepared statement usage
- }), &gorm.Config{})
复制代码 3.7.2 连接PostgreSQL配置解析
- dsn := "host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai"
复制代码 上述示例中的 DSN 解析如下:
- user=gorm:数据库用户名。
- password=gorm:数据库密码。
- dbname=gorm:数据库名称。
- port=9920:数据库连接端口。
- sslmode=disable:禁用 SSL 模式。
- TimeZone=Asia/Shanghai:设置时区。
根据实际情况,你需要替换这些值为你的 PostgreSQL 数据库连接信息。
3.7.3 自定义 PostgreSQL 驱动
GORM 允许通过 DriverName 选项自定义 PostgreSQL 驱动,例如:- import (
- _ "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/postgres"
- "gorm.io/gorm"
- )
- db, err := gorm.Open(postgres.New(postgres.Config{
- DriverName: "cloudsqlpostgres",
- DSN: "host=project:region:instance user=postgres dbname=postgres password=password sslmode=disable",
- })
复制代码 3.7.4 现有的数据库连接PostgreSQL
GORM 允许通过一个现有的数据库连接来初始化 *gorm.DB- import (
- "database/sql"
- "gorm.io/driver/postgres"
- "gorm.io/gorm"
- )
- sqlDB, err := sql.Open("pgx", "mydb_dsn")
- gormDB, err := gorm.Open(postgres.New(postgres.Config{
- Conn: sqlDB,
- }), &gorm.Config{})
复制代码 3.8 连接SQLite
3.8.1 连接SQLite举例
- package main
- import (
- "gorm.io/driver/sqlite"
- "gorm.io/gorm"
- )
- type Product struct {
- gorm.Model
- Code string
- Price uint
- }
- func main() {
- dsn := "test.db" // SQLite数据库文件路径
- db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})
- if err != nil {
- panic("failed to connect database")
- }
- defer db.DB()
- // 迁移 schema
- db.AutoMigrate(&Product{})
- // 创建记录
- db.Create(&Product{Code: "D42", Price: 100})
- // 查询记录
- var product Product
- db.First(&product, 1)
- db.First(&product, "code = ?", "D42")
- // 更新记录
- db.Model(&product).Update("Price", 200)
- db.Model(&product).Updates(Product{Price: 200, Code: "F42"})
- db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
- // 删除记录
- db.Delete(&product, 1)
- }
复制代码 3.8.2 连接SQLite配置解析
上述示例中的 test.db 是 SQLite 数据库文件的路径。你可以根据实际情况调整文件路径。
3.9 连接SQL Server
3.9.1 连接SQL Server举例
- package main
- import (
- "gorm.io/driver/sqlserver"
- "gorm.io/gorm"
- )
- type Product struct {
- gorm.Model
- Code string
- Price uint
- }
- func main() {
- dsn := "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"
- db, err := gorm.Open(sqlserver.Open(dsn), &gorm.Config{})
- if err != nil {
- panic("failed to connect database")
- }
- defer db.DB()
- // 迁移 schema
- db.AutoMigrate(&Product{})
- // 创建记录
- db.Create(&Product{Code: "D42", Price: 100})
- // 查询记录
- var product Product
- db.First(&product, 1)
- db.First(&product, "code = ?", "D42")
- // 更新记录
- db.Model(&product).Update("Price", 200)
- db.Model(&product).Updates(Product{Price: 200, Code: "F42"})
- db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})
- // 删除记录
- db.Delete(&product, 1)
- }
复制代码 3.9.2 连接SQL Server配置解析
- dsn := "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"
复制代码 上述示例中的 DSN 解析如下:
- gorm
oremIpsum86:用户名和密码。
- localhost:9930:数据库服务器地址和端口。
- database=gorm:数据库名称。
3.10 连接TiDB
3.10.1 连接TiDB举例
iDB 兼容 MySQL 协议。 因此你可以按照 MySQL 一节来创建与 TiDB 的连接。
在使用 TiDB 时有一些值得注意的内容:
- 您可以在结构体中使用 gorm:"primaryKey;default:auto_random()" 标签从而调用 TiDB 的 AUTO_RANDOM 功能。
- TiDB supported SAVEPOINT from v6.2.0, please notice the version of TiDB when you use this feature.
- TiDB supported FOREIGN KEY from v6.6.0, please notice the version of TiDB when you use this feature.
- package main
- import (
- "fmt"
- "gorm.io/driver/mysql"
- "gorm.io/gorm"
- )
- type Product struct {
- ID uint `gorm:"primaryKey;default:auto_random()"`
- Code string
- Price uint
- }
- func main() {
- dsn := "root:@tcp(127.0.0.1:4000)/test"
- db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
- if err != nil {
- panic("failed to connect database")
- }
- db.AutoMigrate(&Product{})
- insertProduct := &Product{Code: "D42", Price: 100}
- db.Create(insertProduct)
- fmt.Printf("insert ID: %d, Code: %s, Price: %d\n",
- insertProduct.ID, insertProduct.Code, insertProduct.Price)
- readProduct := &Product{}
- db.First(&readProduct, "code = ?", "D42") // find product with code D42
- fmt.Printf("read ID: %d, Code: %s, Price: %d\n",
- readProduct.ID, readProduct.Code, readProduct.Price)
- }
复制代码 3.10.2 连接TiDB配置解析
- dsn := "root:@tcp(127.0.0.1:4000)/test"
复制代码
- root: 数据库用户名。在这里,用户名是 "root"。
- @: 分隔用户名和密码的分隔符。
- "": 数据库密码。在这里,密码是空字符串,表示没有密码。
- tcp(127.0.0.1:4000): 数据库服务器的地址和端口。在这里,MySQL 服务器位于本地主机(127.0.0.1),端口是 4000。
- /test: 数据库名称。在这里,数据库名是 "test"。
3.10 连接Clickhouse
3.10.1 连接Clickhouse举例
- package main
- import (
- "gorm.io/driver/clickhouse"
- "gorm.io/gorm"
- )
- type User struct {
- gorm.Model
- Name string
- Age int
- }
- func main() {
- dsn := "tcp://localhost:9000?database=gorm&username=gorm&password=gorm&read_timeout=10&write_timeout=20"
- db, err := gorm.Open(clickhouse.Open(dsn), &gorm.Config{})
- if err != nil {
- panic("failed to connect database")
- }
- // 自动迁移 (这是GORM自动创建表的一种方式--译者注)
- db.AutoMigrate(&User{})
- // 设置表选项
- db.Set("gorm:table_options", "ENGINE=Distributed(cluster, default, hits)").AutoMigrate(&User{})
- // 插入
- db.Create(&user)
- // 查询
- db.Find(&user, "id = ?", 10)
- // 批量插入
- var users = []User{user1, user2, user3}
- db.Create(&users)
- // ...
- }
复制代码 3.10.2 连接Clickhouse配置解析
- dsn := "tcp://localhost:9000?database=gorm&username=gorm&password=gorm&read_timeout=10&write_timeout=20"
复制代码 上述示例中的 DSN 解析如下:
- tcp://localhost:9000: ClickHouse 服务器的地址和端口。在这里,ClickHouse 服务器位于本地主机(localhost),端口是 9000。这是 ClickHouse 的默认端口。
- ?: 连接参数的起始标志。
- database=gorm: 数据库名称。在这里,数据库名是 "gorm"。
- username=gorm: 数据库用户名。在这里,用户名是 "gorm"。
- password=gorm: 数据库密码。在这里,密码是 "gorm"。
- read_timeout=10: 读取超时时间。在这里,设置为 10 秒。
- write_timeout=20: 写入超时时间。在这里,设置为 20 秒。
你需要根据实际情况替换这些值。
四、连接池
GORM 使用 database/sql 来维护连接池- sqlDB, err := db.DB()
- // SetMaxIdleConns sets the maximum number of connections in the idle connection pool.
- sqlDB.SetMaxIdleConns(10)
- // SetMaxOpenConns sets the maximum number of open connections to the database.
- sqlDB.SetMaxOpenConns(100)
- // SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
- sqlDB.SetConnMaxLifetime(time.Hour)
复制代码 五、MySQL 其他配置
注意:想要正确的处理 time.Time ,您需要带上 parseTime 参数, (更多参数) 要支持完整的 UTF-8 编码,您需要将 charset=utf8 更改为 charset=utf8mb4 查看 此文章 获取详情
MySQl 驱动程序提供了 一些高级配置 可以在初始化过程中使用,例如:- db, err := gorm.Open(mysql.New(mysql.Config{
- DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // DSN data source name
- DefaultStringSize: 256, // string 类型字段的默认长度
- DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
- DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
- DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
- SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
- }), &gorm.Config{})
复制代码 六、加入日志打印sql
6.1 打印日志
Gorm 有一个 默认 logger 实现,默认情况下,它会打印慢 SQL 和错误
Logger 接受的选项不多,您可以在初始化时自定义它,例如:- newLogger := logger.New(
- log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
- logger.Config{
- SlowThreshold: time.Second, // 慢 SQL 阈值
- LogLevel: logger.Silent, // 日志级别
- IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
- Colorful: false, // 禁用彩色打印
- },
- )
- // 全局模式
- db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
- Logger: newLogger,
- })
- // 新建会话模式
- tx := db.Session(&Session{Logger: newLogger})
- tx.First(&user)
- tx.Model(&user).Update("Age", 18)
复制代码 6.2 日志级别
GORM 定义了这些日志级别:Silent、Error、Warn、Info- db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
- Logger: logger.Default.LogMode(logger.Silent),
- })
复制代码 6.3 Debug
Debug 单个操作,将当前操作的 log 级别调整为 logger.Info- db.Debug().Where("name = ?", "jinzhu").First(&User{})
复制代码 6.4 具体代码
- package main
- import (
- "gorm.io/driver/mysql"
- "gorm.io/gorm"
- "gorm.io/gorm/logger"
- "log"
- "os"
- "time"
- )
- type User struct {
- ID int
- }
- func main() {
- // 日志配置
- newLogger := logger.New(
- log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
- logger.Config{
- SlowThreshold: time.Second, // 慢 SQL 阈值
- LogLevel: logger.Info, // 日志级别为info
- IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
- Colorful: true, // 彩色打印
- },
- )
- dsn := "root:123@tcp(127.0.0.1:3306)/gorm_test?charset=utf8mb4&parseTime=True&loc=Local"
- db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
- Logger: newLogger,
- })
- if err != nil {
- panic(err) // 如果数据库不存在会报错
- }
- db.AutoMigrate(&User{})
- }
复制代码 七、参考文档
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |