数据库连接
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"testing"
)
// 测试连接mysql
func TestConnectMysql(t *testing.T) {
dsn := "root:1234@(127.0.0.1:3306)/SimpleGorm?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
}
gorm.Open第一个参数是Dialector类型
-
简单的,直接按照数据库的地址构造dialector 即mysql.Opne(dsn)
-
复杂的,支持MySQL的配置
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.Open的第二个参数是Option类型,可以设置gorm的配置
-
支持的配置有如下
type Config struct { SkipDefaultTransaction bool //跳过默认事务 NamingStrategy schema.Namer // 表和列命名策略 Logger logger.Interface // 配置日志 NowFunc func() time.Time // 更改创建时间使用的函数 DryRun bool //生成 SQL 但不执行,可以用于准备或测试生成的 SQL PrepareStmt bool //在执行任何 SQL 时都会创建一个 prepared statement 并将其缓存,以提高后续的效率 DisableNestedTransaction bool // 禁用嵌套事务 AllowGlobalUpdate bool // 启用全局 update/delete DisableAutomaticPing bool //GORM 会自动 ping 数据库以检查数据库的可用性.可以禁用 DisableForeignKeyConstraintWhenMigrating bool //GORM 会自动创建外键约束,若要禁用该特性 建议禁用物理外键 } -
使用示例,只用了一个配置
db, _ = gorm.Open(mysql.Open(dsn), &gorm.Config{ DisableForeignKeyConstraintWhenMigrating: true, //禁用物理外键 })
可用标签见文档
示例:
// 定义一个玩家结构
type Player struct {
ID uint `gorm:"primaryKey;comment:主键"`
UID uint `gorm:"unique;comment:玩家唯一id"`
Username string `gorm:"comment:玩家用户名"`
Password string `gorm:"comment:密码"`
CreatedAt time.Time `gorm:"comment:创建时间;autoCreateTime"`
UpdateAt time.Time `gorm:"comment:创建时间;autoUpdateTime"`
DeleteAt gorm.DeletedAt `gorm:"删除时间"`
}
gorm也提供了基本的模型,已经包含了如下字段:
type Model struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt DeletedAt `gorm:"index"`
}
自己创建模型时,直接继承就可以了,例如
type Player struct {
gorm.Model // gorm提供的结构体,自带idCreateatupdateatdeleteat
UID uint `gorm:"unique;comment:玩家唯一id"`
Username string `gorm:"comment:玩家用户名"`
Password string `gorm:"comment:密码"`
}
基本的增删改查
增删改查可以根据返回值的RowsAffected来判断,表示数据库操作影响的行数.
gorm会自动跳过软删除的数据
gorm执行前添加Debug会进入调试模式,打印所有sql
db.Debug().Where("username like ?","%夏目%").Find(&newPlayers) // 加入DeBug()方便打印sql进行调试
创建表
exist := db.Migrator().HasTable(&Player{}) // 查看Player表是否存在
if !exist{
db.AutoMigrate(&Player{})
}
插入
player := Player{
Username: "夏目",
Password: "1234",
UID: 12345678,
}
result := db.Save(&player)
删除
db.First(&player) // 删除第一条数据 result := db.Delete(&player)
查询单条
db.First(&player) //首条记录
db.First(&newPlayer,4) // 主键查询
db.Where("Username = ?","xiamu").First(&player) //条件查询
查询多条
db.Find(&players)
db.Debug().Where("username like ?","%夏目%").Find(&newPlayers)
一对一
hasOne一对一包含两种, has one以及belongs to
type Player struct {
gorm.Model // gorm提供的结构体,自带idCreateatupdateatdeleteat
UID uint `gorm:"unique;comment:玩家唯一id"`
Username string `gorm:"comment:玩家用户名"`
Password string `gorm:"comment:密码"`
Role Role
}
// 定义一个游戏角色 使用playerId作为外键
type Role struct {
gorm.Model
PlayerId uint // 默认使用user.uid作为外键
Name string `gorm:"comment:游戏角色名"`
Level string `gorm:"comment:游戏角色登记"`
Coins uint32 `gorm:"comment:游戏角色金币数"`
}
Player has Role 每个玩家包含一个角色.
-
Player中要包含一个Role结构体
-
Role中要包含Player的外键,默认为PlayerId (结构体名Id)
-
支持自定义外键
Phone Phone `gorm:"foreignKey:UID"` // 自定义外键 Role中的外键也要对应修改
-
也支持自定义引用 必须是有效的外键,即unique列
type Player struct {
gorm.Model // gorm提供的结构体,自带idCreateatupdateatdeleteat
Username string `gorm:"comment:玩家用户名"`
Password string `gorm:"comment:密码"`
SwordID uint `gorm:"comment:宝剑ID"`
Sword Sword
}
type Sword struct {
gorm.Model
Name string `gorm:"comment:宝剑名;unique"`
}
一把Sword属于一个Player
-
Player中包含Sword的主键以及Sword的结构体
-
支持拥有者(Player)中修改Player.SwordName的名字
type Player struct { ... MySwordID string Sword Sword `gorm:"foreignKey:MySwordID"` } -
支持修改引用: 可以修改Player.SwordID的内容为指定的Sword中的字段
Sword Sword `gorm:"references:Name"` // SwordID保存的即变为Sword.Name
增:
player1 := Player{
Username: "周芷若",
Password: "1234",
Sword: Sword{
Name: "倚天剑",
},
}
player2 := Player{
Username: "张无忌",
Password: "1234",
Sword: Sword{
Name: "屠龙刀",
},
}
db.Create([]Player{player1,player2})
删除和普通表的操作一样.
更新和查询见关联查询以及preload的用法
一对多数据关系: player和hero是一对多关系
type Player struct {
gorm.Model // gorm提供的结构体,自带idCreateatupdateatdeleteat
Username string `gorm:"comment:玩家用户名"`
Password string `gorm:"comment:密码"`
//Heros []Hero
// 第二种
//Heros []Hero `gorm:"foreignKey:PlayerKey"` // 定义外键的名字
// 第三种
Heros []Hero `gorm:"foreignKey:PlayerName;references:Username"` // 自定义外键引用
}
// hero player可以拥有多个hero
type Hero struct {
gorm.Model
Name string `gorm:"comment:英雄名字"`
HP int32 `gorm:"comment:血量"`
//PlayerID uint
// 第二种
//PlayerKey uint
// 第三种
PlayerName string
}
插入数据
func TestInsert(t *testing.T){
hero1 := Hero{
Name: "卡莎",
HP: 300,
}
hero2 := Hero{
Name: "瑞兹",
HP: 500,
}
player := Player{
Username: "夏目",
Password: "1234",
Heros: []Hero{hero1,hero2},
}
result := db.Create(&player)
fmt.Println("插入行数:",result.RowsAffected)
}
多对多
每个player都有多个手柄
// 每一个player有多个手柄
type Player struct {
gorm.Model
Name string
Gamepads []Gamepad `gorm:"many2many:player_gamepad"`
Friends []Player `gorm:"many2many:player_friends"` //自引用
}
// 游戏手柄
type Gamepad struct {
gorm.Model
Brand string
}
插入数据
func TestInsert(t *testing.T) {
gamepad1 := Gamepad{
Brand: "Nintendo",
}
gamepad2 := Gamepad{
Brand: "PS4",
}
db.Create([]*Gamepad{&gamepad1,&gamepad2}) // 插入手柄数据
gamepads := make([]Gamepad,0)
db.Find(&gamepads)
player1 := Player{
Name: "马里奥",
Gamepads: gamepads, // 每个player都有各种手柄
}
player2 := Player{
Name: "路易吉",
Gamepads: gamepads,
}
result := db.Create([]*Player{&player1,&player2}) //插入数据,gorm自动更新中间表
if result.RowsAffected==0 {
fmt.Println("插入失败")
}else{
fmt.Println("插入成功",result.RowsAffected)
}
}
关联
一对一; 一对多; 多对多的查询都需要使用关联查询.. 文档写的很好了,我就懒得写了
关键字: Assocaition
功能包括:
-
查找所有关联
-
添加关联: 例如给player添加新的gamepad
-
替换关联
-
删除关联
-
清空关联
-
关联计数
-
删除数据,如果要删除它关联的数据,要使用Select删除
查询数据时, 如果要把关联的数据一并查找出来, 可以使用预加载
-
支持全部查找
-
支持带条件的预加载
-
也支持自定义的预加载
db.Preload("Orders", func(db *gorm.DB) *gorm.DB { return db.Order("orders.amount DESC") }).Find(&users)
如果一个模型 struct要在创建查询更新删除操作时, 添加自定义的方法, 可以使用钩子函数来实现, 这样gorm就会自动在执行相关操作时, 执行对应的函数
-
创建时
-
BeforeSave
-
BeforeCrete
-
AfterCreate
-
AfterSave
-
-
更新时
-
BeforeSave
-
BeforeUpdate
-
AfterUpdate
-
AfterSave
-
-
删除时
-
BeforeDelete
-
AfterDelete
-
-
查询时
-
AfterFind 比如把密码加密,
-
db.Raw(“原生sql”).Scan(查找对象)
db.Exec(“原生sql”)
迁移Migrator方法包含了很多对数据表的操作方法
-
AutoMigrate 自动迁移
-
CurrentDatabase 当前数据库
-
FullDataTypeOf(Field) 列的数据类型
表的操作
-
CreateTable 创建表
-
DropTable 删除表
-
HasTable
-
RenameTable
列的操作
-
AddColumn
-
DropColumn
-
AlterColumn
-
HasColumn
-
RenameColumn
-
MigrateColumn
-
ColumnTypes
约束操作
-
CreateConstraint
-
DropConstraint
-
HashConstraint
索引操作
-
CreateIndex
-
DropIndex
-
HasIndex
-
RenameIndex
// 开始事务 tx := db.Begin() // 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db') tx.Create(...)// ... // 遇到错误时回滚事务 tx.Rollback() // 否则,提交事务 tx.Commit()
如果需要回滚到指定的地方,可以使用:
-
tx.SavePoint(“name”)
-
tx.RollbackTo(“name”)
回滚到指定的保存点



