Gorm 入门介绍与基本使用

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的特性包括:

  1. 模型定义和操作:
    • 全功能 ORM
    • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
    • Create,Save,Update,Delete,Find 中的钩子方法
    • 支持 PreloadJoins 的预加载
    • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
    • 复合主键,索引,约束
  2. 事务处理和数据库操作:
    • 事务,嵌套事务,Save Point,Rollback To Saved Point
    • Context、预编译模式、DryRun 模式
    • SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
    • Auto Migration
  3. 其他功能:
    • 自定义 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:

import "gorm.io/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)
}

请注意替换usernamepassworddbname为你自己的数据库信息。这里使用了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 ServerTiDB

有些数据库可能兼容 mysqlpostgres 的方言,在这种情况下,你可以直接使用这些数据库的方言。

对于其它不兼容的情况,您可以自行编写一个新驱动,这需要实现 方言接口

参考官网文档:【编写新驱动】

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配置解析

dsn := "test.db"

上述示例中的 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:LoremIpsum86:用户名和密码。
  • 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 定义了这些日志级别:SilentErrorWarnInfo

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{})
}

七、参考文档

本文作者:贾维斯Echo

本文链接:https://www.cnblogs.com/taoxiaoxin/p/17956555

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   贾维斯Echo  阅读(573)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
  2. 2 稻香 稻香 (2015中国好声音第四季现场) - 周杰伦;徐林;Will Jay
404 not found - REOL
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作曲 : Reol

作词 : Reol

fade away...do over again...

fade away...do over again...

歌い始めの一文字目 いつも迷ってる

歌い始めの一文字目 いつも迷ってる

どうせとりとめのないことだけど

伝わらなきゃもっと意味がない

どうしたってこんなに複雑なのに

どうしたってこんなに複雑なのに

噛み砕いてやらなきゃ伝わらない

ほら結局歌詞なんかどうだっていい

僕の音楽なんかこの世になくたっていいんだよ

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.

目の前 広がる現実世界がまた歪んだ

目の前 広がる現実世界がまた歪んだ

何度リセットしても

僕は僕以外の誰かには生まれ変われない

「そんなの知ってるよ」

気になるあの子の噂話も

シニカル標的は次の速報

麻痺しちゃってるこっからエスケープ

麻痺しちゃってるこっからエスケープ

遠く遠くまで行けるよ

安定なんてない 不安定な世界

安定なんてない 不安定な世界

安定なんてない きっと明日には忘れるよ

fade away...do over again...

fade away...do over again...

そうだ世界はどこかがいつも嘘くさい

そうだ世界はどこかがいつも嘘くさい

綺麗事だけじゃ大事な人たちすら守れない

くだらない 僕らみんなどこか狂ってるみたい

本当のことなんか全部神様も知らない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.