📦 GORMv2
🏆 GORM
⭐️ GORM
是一个使用 GO
编写的 ORM
框架,它让你的数据库里面的表结构变成代码定义的数据结构,从而做到,代码结构体即为数据结构,即为数据行为
如果学过 JavaWeb
可以把它理解为 Mybatis
🌟 安装 GORM
并连接数据库
同样也是使用 go get
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql //下载驱动
安装完毕之后就可以连接数据库了,GORM
官方支持的数据库类型有:MySQL
, PostgreSQL
, SQLite
, SQL Server
和 TiDB
,这里我们使用 Mysql
,它的连接方法和原生 sql
库类似
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
database := "root:000000@tcp(localhost:3306)/gotest?charset=utf8mb4&parseTime=True&loc=Local"
db,err := gorm.Open(mysql.Open(database),&gorm.Config{
SkipDefaultTransaction: false, // 禁用默认事务
NamingStrategy: schema.NamingStrategy{ // 命名策略
TablePrefix: "GORM", //默认创建表的前缀
SingularTable: true, // 禁用表名复数,如果是users表,则创建的表名就是user
},
DisableForeignKeyConstraintWhenMigrating: true, // 禁用外键约束
})
if err != nil {
fmt.Println("连接错误",err)
}
fmt.Println(name)
}
⭕️ 那么开始解读这段代码: 首先先是创建了一个字符串,这个连接格式就是 sql
原生库的连接格式,建议在看看 GoWeb
中的 sql
原生库,如何使用 gorm.Open()
连接数据库,可以看一下 Open
的函数签名,它接接收一个 Dialector
;类对象和多个 Option
对象,是 gorm
配置,它返回了一个DB对象和错误
func Open(dialector Dialector, opts ...Option) (db *DB, err error)
使用 mysql.Opent
它接收一个字符串,用来连接数据库,它返回的就是一个 Dialector
对象
func Open(dsn string) gorm.Dialector {
dsnConf, _ := mysql.ParseDSN(dsn)
return &Dialector{Config: &Config{DSN: dsn, DSNConfig: dsnConf}}
}
上面只是一种简单的连接方法,还有一种高级配置:
func main() {
database := "root:000000@tcp(localhost:3306)/gotest?charset=utf8mb4&parseTime=True&loc=Local"
db,err := gorm.Open(mysql.New(mysql.Config{
DSN: database, // 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{
SkipDefaultTransaction: false, // 禁用默认事务
NamingStrategy: schema.NamingStrategy{ // 命名策略
TablePrefix: "GORM", //默认创建表的前缀
SingularTable: true, // 禁用表名复数,如果是users表,则创建的表名就是user
},
DisableForeignKeyConstraintWhenMigrating: true, // 禁用外键约束
})
if err != nil {
fmt.Println("连接错误",err)
}
fmt.Println(db)
}
使用的是 mysql.New
它接收的是一个 config
,用于配置连接时候的配置
// mysql.Config可配置项
type Config struct {
DriverName string // 驱动名称,指定使用哪个数据库驱动。
ServerVersion string // 服务器版本,用于指定连接的数据库服务器版本。
DSN string // 数据源名称,包含了连接数据库所需的详细信息。
DSNConfig *mysql.Config // 数据源配置,提供了一个配置对象,用于设置连接参数。
Conn gorm.ConnPool // 连接池,用于管理数据库连接。
SkipInitializeWithVersion bool // 是否跳过使用版本信息初始化。
DefaultStringSize uint // 默认字符串大小,用于设置默认的字符串字段长度。
DefaultDatetimePrecision *int // 默认日期时间精度,用于设置日期时间字段的精度。
DisableWithReturning bool // 是否禁用 MySQL 8.0+ 的 WITH RETURNING 功能。
DisableDatetimePrecision bool // 是否禁用日期时间字段的自动精度设置。
DontSupportRenameIndex bool // 是否不支持重命名索引。
DontSupportRenameColumn bool // 是否不支持重命名列。
DontSupportForShareClause bool // 是否不支持 FOR SHARE 子句,用于行锁。
DontSupportNullAsDefaultValue bool // 是否不支持将 NULL 作为默认值。
DontSupportRenameColumnUnique bool // 是否不支持将重命名的列设置为唯一。
// MySQL 8.0.19 版本开始,ALTER TABLE 允许使用更通用(且符合 SQL 标准)的语法
// 来删除和修改任何类型的现有约束。
// 详见 https://dev.mysql.com/doc/refman/8.0/en/alter-table.html
DontSupportDropConstraint bool // 是否不支持删除约束。
}
&gorm.Config{}
内配置 gorm
的配置https://gorm.io/zh_CN/docs/gorm_config.html
type Config struct {
SkipDefaultTransaction bool
NamingStrategy schema.Namer
Logger logger.Interface
NowFunc func() time.Time
DryRun bool
PrepareStmt bool
DisableNestedTransaction bool
AllowGlobalUpdate bool
DisableAutomaticPing bool
DisableForeignKeyConstraintWhenMigrating bool
}
🌟 创建数据表
🍵 AutoMigrate
🔝 在 Grom
中使用 AutoMigrate
来自动创建数据表,自动比较应用程序中的数据模型(通常是用代码定义的模型类或结构体,代表数据库表的结构)与数据库当前的实际 schema
。如果发现两者之间存在差异,如模型中新增了一个字段而数据库表中没有,AutoMigrate
会自动执行必要的 SQL
命令来更新数据库 schema
,确保数据库结构与你的代码模型相匹配。这样可以简化开发过程,避免手动编写和执行复杂的 ALTER TABLE
等 SQL
语句来调整数据库结构,
⭐️AutoMigrate
方法进行表结构迁移时,默认情况下它只会添加新的字段和必要的索引,而不会自动删除不再使用的字段
⭐️schema
是数据库的结构描述,包括表、列、索引、约束等数据库对象的定义。它定义了数据库中数据的组织方式和规则。
AutoMigrate
可以接收多个类型
// AutoMigrate run auto migration for given models
func (db *DB) AutoMigrate(dst ...interface{}) error {
return db.Migrator().AutoMigrate(dst...)
}
⚠️ 注意: AutoMigrate
会创建表、缺失的外键、约束、列和索引。 如果大小、精度、是否为空可以更改,则 AutoMigrate
会改变列的类型。 出于保护您数据的目的,它 不会 删除未使用的列
// User 创建结构体对应表
type User struct {
Name string
Password string
}
func main() {
....
//创建数据表
err = db.AutoMigrate(&User{})
if err!= nil {
fmt.Println("创建数据表错误",err)
}
fmt.Println("创建数据表成功!!")
}
测试运行,进入数据库查看是否创建了数据表,由于之前设置了创建数据表前缀 gorm
,所以创建出来的数据表为 gormuser
MariaDB [gorm]> show tables;
+----------------+
| Tables_in_gorm |
+----------------+
| gormuser |
+----------------+
1 row in set (0.001 sec)
MariaDB [gorm]> desc gormuser;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| name | varchar(256) | YES | | NULL | |
| password | varchar(256) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
2 rows in set (0.014 sec)
🍵 Migrator
接口
如果之前看过 AutoMigrate
的源代码就知道,AutoMigrate
其实就是调用的 Migrator
,Migrator是一个对数据库内其他操作的接口,
// Migrator 接口提供了数据库结构迁移的相关方法,包括表、列、索引、视图和约束的创建、修改、删除等操作。
type Migrator interface {
// AutoMigrate 自动检测并迁移模型结构到数据库,例如新增字段、修改字段类型等。
AutoMigrate(dst ...interface{}) error
// CurrentDatabase 返回当前操作的数据库名称。
CurrentDatabase() string
// FullDataTypeOf 根据字段元数据生成其在数据库中的完整数据类型表达式。
FullDataTypeOf(field *schema.Field) clause.Expr
// CreateTable 根据提供的模型结构创建数据库表。
CreateTable(dst ...interface{}) error
// DropTable 根据模型删除对应的数据库表。
DropTable(dst ...interface{}) error
// HasTable 判断指定模型对应的数据库表是否存在。
HasTable(dst interface{}) bool
// RenameTable 重命名数据库中的表。
RenameTable(oldName, newName interface{}) error
// GetTables 获取数据库中的所有表名列表。
GetTables() (tableList []string, err error)
// AddColumn 向指定表添加一个新的列。
AddColumn(dst interface{}, field string) error
// DropColumn 从指定表中删除一个列。
DropColumn(dst interface{}, field string) error
// AlterColumn 修改指定表中列的定义。
AlterColumn(dst interface{}, field string) error
// MigrateColumn 迁移指定列的数据类型或属性至新的定义。
MigrateColumn(dst interface{}, field *schema.Field, columnType ColumnType) error
// HasColumn 检查指定表中是否存在某列。
HasColumn(dst interface{}, field string) bool
// RenameColumn 重命名指定表中的列。
RenameColumn(dst interface{}, oldName, newName string) error
// ColumnTypes 获取指定表中各列的数据类型。
ColumnTypes(dst interface{}) ([]ColumnType, error)
// CreateView 创建数据库视图。
CreateView(name string, option ViewOption) error
// DropView 删除指定的数据库视图。
DropView(name string) error
// CreateConstraint 创建数据库表的约束条件。
CreateConstraint(dst interface{}, name string) error
// DropConstraint 删除数据库表的约束条件。
DropConstraint(dst interface{}, name string) error
// HasConstraint 检查数据库表中是否存在特定的约束条件。
HasConstraint(dst interface{}, name string) bool
// CreateIndex 为指定表创建索引。
CreateIndex(dst interface{}, name string) error
// DropIndex 删除指定表中的索引。
DropIndex(dst interface{}, name string) error
// HasIndex 判断指定表中是否存在某个索引。
HasIndex(dst interface{}, name string) bool
// RenameIndex 重命名指定表中的索引。
RenameIndex(dst interface{}, oldName, newName string) error
}
1️⃣ 对表操作
//使用迁移器
dbMigrate := db.Migrator()
//检查是否存在表,如果已经存在则删除,也就是删除表
dbMigrate.DropTable(&User{})
//创建数据表
err = dbMigrate.AutoMigrate(&User{})
if err != nil {
fmt.Println("创建数据表错误", err)
}
fmt.Println("创建数据表成功!!")
//检查对应类型User的数据表是不是存在
if dbMigrate.HasTable(&User{}) {
//或者dbMigrate.HasTable("user")
fmt.Println("数据表存在")
} else {
fmt.Println("数据表不存在")
}
// 重命名表,这里也可以填两个类型
dbMigrate.RenameTable(&User{}, "GORM_user")
//如: db.Migrator().RenameTable(&User{}, &UserInfo{})
2️⃣ 对列操作
// User 创建结构体对应表
type User struct {
Name string
Password string
Email string
}
//添加列,注意这里需要在结构体中添加email字段
err = dbMigrate.AddColumn(&User{}, "Email")
if err != nil {
fmt.Println("添加列错误", err)
return
}
//删除列
err = dbMigrate.DropColumn(&User{}, "email")
if err != nil {
fmt.Println("删除列错误", err)
}
//修改列
dbMigrate.AlterColumn(&User{}, "email")
//检查是否存在
column := dbMigrate.HasColumn(&User{}, "email")
if column {
fmt.Println("存在")
} else {
fmt.Println("不存在")
}
//字段重命名
err = dbMigrate.RenameColumn(&User{}, "email", "email_address")
if err != nil {
fmt.Println("字段重命名错误", err)
}
//获取字段的类型
types, err := db.Migrator().ColumnTypes(&User{})
if err != nil {
fmt.Println("获取字段类型错误", err)
}
for _, v := range types {
fmt.Println(v.Name(), v.ScanType(), v.DatabaseTypeName())
}