【笔记】Go语言通过Gorm操作Mysql数据库

前言

Go语言通过Gorm操作Mysql数据库

下载依赖

1
2
go get gorm.io/gorm
go get gorm.io/driver/mysql

获取数据库连接

<username>:用户名
<password>:密码
<ip>:IP
<port>:端口号
<databasename>:数据库名

charset=utf8mb4:指定字符集

&gorm.Config{}:指定配置

QueryFields: true:输出执行的SQL日志
SkipDefaultTransaction: true:禁用事务

1
2
3
4
5
6
7
8
9
10
11
package main

import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)

func main() {
dsn := "<username>:<password>@tcp(<ip>:<port>)/<databasename>?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
}

创建实体

  • 继承gorm.Model结构体
  • 结构体名
    • 如果结构体名是User,那么映射的数据表名默认为users
      • 默认情况下数据表名默认为复数
    • 如果结构体名是UserTable,那么映射的数据表名默认为user_table
  • 字段名
    • 如果字段名是ID,那么映射的数据表字段名默认为id
    • 如果字段名是UserID,那么映射的数据表名默认为user_id

TableName():重新映射表名

1
2
3
4
5
6
7
8
type User struct {
gorm.Model
Username string
}

func (User) TableName() string {
return "user"
}

新增

1
2
3
user := User{ID: 1, Username: ""}

db.Create(&user)

删除

1
2
3
user := User{ID: 1}

db.Delete(&user)

添加条件

1
2
3
user := User{}

db.Where("id > 1").Delete(&user)

修改

覆盖

  • 覆盖所有字段,无论是否为零值
  • 如果数据存在,则覆盖;如果数据不存在,则新增
1
2
3
user := User{ID: 1, Username: ""}

db.Save(&user)

更新

修改单个字段

  • 通过Model()指定结构体,间接指定数据表名
1
2
3
user := User{}

db.Model(&user).Where("id = 1").Update("Username", "")
  • 通过Table()直接指定数据表名
1
2
3
user := User{}

db.Table("user").Where("id = 1").Update("Username", "")

更新所有字段

  • 只修改非零值的字段,零值字段自动跳过
通过结构体更新
  • 通过Model()指定结构体,间接指定数据表名
1
2
3
user := User{Username: ""}

db.Model(&user).Updates(&user)
  • 通过Table()直接指定数据表名
1
2
3
user := User{Username: ""}

db.Table("user").Updates(&user)
通过映射更新
1
2
3
user := map[string]string{"Username": ""}

db.Table("user").Updates(&user)

查询

Where子句

查询全部数据

1
2
3
userList := []User{}

db.Find(&userList)

查询单条数据

1
2
3
user := User{ID: 1}

db.Find(&user)
查询结果集的第一条数据
1
2
3
userList := []User{}

db.First(&userList)

根据条件查询数据

占位符
1
2
3
userList := []User{}

db.Where("id > ?", 1).Find(&userList)
算数运算
相等运算
  • 获取第一次匹配的数据
1
2
3
user := User{}

db.Where("id = ?", 1).Find(&user)
  • 获取所有匹配的数据
1
2
3
userList := []User{}

db.Where("id <> ?", 1).Find(&userList)
其他算数运算

>:大于
<:小于
>=:大于等于
<=:小于等于
!=:不等于

1
2
3
userList := []User{}

db.Where("id > ?", 1).Find(&userList)
包含判断
  • 查询id等于0或等于2的数据
1
2
3
userList := []User{}

db.Where("id IN (?)", []int{0, 2}).Find(&userList)
模糊查询
1
2
3
userList := []User{}

db.Where("id LIKE ?", "%1%").Find(&userList)
逻辑运算
  • 查询id大于0且小于2的数据
1
2
3
userList := []User{}

db.Where("id > ? AND id < ?", 0, 2).Find(&userList)
  • 查询id等于0或等于2的数据
1
2
3
userList := []User{}

db.Where("id = ? OR id = ?", 0, 2).Find(&userList)
1
2
3
userList := []User{}

db.Where("id = ?", 0).Or("id = ?", 2).Find(&userList)
时间判断
1
2
3
userList := []User{}

db.Where("time > ?", time).Find(&userList)
区间判断
在…之间
  • 查询id大于等于0小于等于2的数据
1
2
3
userList := []User{}

db.Where("id BETWEEN ? AND ?", 0, 2).Find(&userList)
不在…之间
  • 查询id小于0并且大于2的数据
1
2
3
userList := []User{}

db.Where("id NOT BETWEEN ? AND ?", 0, 2).Find(&userList)
空判断
1
2
3
userList := []User{}

db.Where("id IS NULL").Find(&userList)
非空
1
2
3
userList := []User{}

db.Where("id IS NOT NULL").Find(&userList)

Select子句

1
2
3
userList := []User{}

db.Select("id, username").Find(&userList)

OrderBy子句

排序单次

1
2
3
userList := []User{}

db.Order("id asc").Find(&userList)

排序多次

1
2
3
userList := []User{}

db.Order("id asc").Order("username desc").Find(&userList)

Limit子句

Offset():跳过几条数据
Limit():每页的数据总数

1
2
3
userList := []User{}

db.Offset(1).Limit(2).Find(&userList)

计算数据总数

1
2
3
4
userList := []User{}
var count int64

db.Find(&userList).Count(&count)

使用原生SQL语句

<sql>:SQL语句

执行没有返回值的SQL语句

1
db.Exec("<sql>")
1
db.Exec("DELETE FROM user WHERE id = ?", 1)

执行有返回值的SQL语句

1
2
3
userList := []User{}

db.Raw("SELECT * FROM user").Scan(&userList)

多表关联

一对一

  • 一个用户映射一个地址

BelongsTo

  • 默认主键在结构体中的属性名是ID,在数据库中的属性名是id
  • 默认外键(逻辑外键)在结构体中的属性名是XxxID,在数据库中的属性名是xxx_id,关联xxx数据表的id字段

foreignKey:属性名:指定外键
reference:ID:指定主键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type User struct {
ID int
Username string
AddressID string
Address Address `gorm:"foreignKey:AddressID;reference:ID"`
}

func (User) TableName() string {
return "user"
}

type Address struct {
ID int
Address string
}

func (Address) TableName() string {
return "address"
}
  • 在查询的同时查询关联表

Address:此处是关联表属性的属性名,用于存放关联表数据

1
2
3
userList := []User{}

db.Preload("Address").Find(&userList)

HasOne

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type User struct {
ID int
Username string
AddressID string
}

func (User) TableName() string {
return "user"
}

type Address struct {
ID int
Address string
User User `gorm:"foreignKey:AddressID;reference:ID"`
}

func (Address) TableName() string {
return "address"
}
  • 在查询的同时查询关联表
1
2
3
addressList := []Address{}

db.Preload("User").Find(&addressList)

多对一

  • 一个地址映射多个用户

HasMany

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type User struct {
ID int
Username string
AddressID string
}

func (User) TableName() string {
return "user"
}

type Address struct {
ID int
Address string
User []User `gorm:"foreignKey:AddressID;reference:ID"`
}

func (Address) TableName() string {
return "address"
}
  • 在查询的同时查询关联表
1
2
3
addressList := []Address{}

db.Preload("User").Find(&addressList)

多对多

  • 查询所有用户及其关联的所有地址

ManyToMany

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
type User struct {
ID int
Username string
Address []Address `gorm:"many2many:user_address"`
}

func (User) TableName() string {
return "user"
}

type Address struct {
ID int
Address string
}

func (Address) TableName() string {
return "address"
}

type UserAddress struct {
ID int
UserID string
AddressID string
}

func (UserAddress) TableName() string {
return "user_address"
}
  • 在查询的同时查询关联表
1
2
3
userList := []User{}

db.Preload("Address").Find(&userList)
排除条件
1
2
3
userList := []User{}

db.Preload("Address", "id != ?", 1).Find(&userList)
将结果重新排序
  • 通过自定义预加载函数实现将结果重新排序
1
2
3
db.Preload("Address", func(db *gorm.DB) *gorm.DB {
return db.Order("id asc")
}).Find(&user)

事务

禁用事务

  • gorm的事务默认是开启的,如果不需要使用事务需要禁用事务
1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)

func main() {
dsn := "<username>:<password>@tcp(<ip>:<port>)/<databasename>?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
SkipDefaultTransaction: true,
})
}

使用事务

开启事务

1
tx := db.Begin()

通过事务执行SQL

1
tx.Create(...)

提交事务

1
tx.Commit()

回滚事务

1
tx.Rollback()
异常情况回滚事务
1
2
3
4
5
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}

完成

参考文献

哔哩哔哩——筱筱知晓
Gorm官方文档