04.其他
# 01.事务
# 1.1 禁用默认事务
为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升。
// 全局禁用
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
SkipDefaultTransaction: true,
})
// 持续会话模式
tx := db.Session(&Session{SkipDefaultTransaction: true})
tx.First(&user, 1)
tx.Find(&users)
tx.Model(&user).Update("Age", 18)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 1.2 事务
package main
import (
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// User 表的结构体ORM映射
type User struct {
ID int64 `json:"id" gorm:"primary_key"`
Name string `json:"name" gorm:"not null" bind:"required"`
Age int `json:"age"`
Birthday time.Time `json:"birthday" gorm:"column:birthday"`
}
func main() {
// 0、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db?charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 1、实现事务操作
db.Transaction(func(tx *gorm.DB) error {
// 当前这个语句是一个正常语句,但是下面的语句由于ID=1的用户已经存在,所以会抛出异常
// 查看数据库可以发现这两天数据都没有创建,实现了事务操作
if err := tx.Create(&User{Name: "root2", Age: 10, Birthday: time.Now()}).Error; err != nil {
return err // 返回任何错误都会回滚事务
}
if err := tx.Create(&User{ID: 1, Birthday: time.Now()}).Error; err != nil {
return err
}
return nil // 返回 nil 提交事务
})
}
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
29
30
31
32
33
34
35
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
29
30
31
32
33
34
35
# 1.3 嵌套事务
- GORM 支持嵌套事务,您可以回滚较大事务内执行的一部分操作
db.Transaction(func(tx *gorm.DB) error {
tx.Create(&user1)
tx.Transaction(func(tx2 *gorm.DB) error {
tx2.Create(&user2)
return errors.New("rollback user2") // Rollback user2
})
tx.Transaction(func(tx2 *gorm.DB) error {
tx2.Create(&user3)
return nil
})
return nil
})
// Commit user1, user3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1.4 手动事务
# 1、方法说明
- Gorm 支持直接调用事务控制方法(commit、rollback)
// 开始事务
tx := db.Begin()
// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
tx.Create(...)
// ...
// 遇到错误时回滚事务
tx.Rollback()
// 否则,提交事务
tx.Commit()
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 2、示例
func CreateAnimals(db *gorm.DB) error {
// 再唠叨一下,事务一旦开始,你就应该使用 tx 处理数据
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
if err := tx.Error; err != nil {
return err
}
if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
tx.Rollback()
return err
}
return tx.Commit().Error
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 1.5 SavePoint、RollbackTo
- GORM 提供了
SavePoint
、Rollbackto
方法,来提供保存点以及回滚至保存点功能
tx := db.Begin()
tx.Create(&user1)
tx.SavePoint("sp1")
tx.Create(&user2)
tx.RollbackTo("sp1") // Rollback user2
tx.Commit() // Commit user1
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 02.连接mysql
# 2.1 基本连接
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
dsn := "root:1@tcp(127.0.0.1:3306)/test_db?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println(err)
}
fmt.Println(db) // &{0xc00018a630 <nil> 0 0xc000198380 1}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- MySQl 驱动程序提供了 一些高级配置 (opens new window) 可以在初始化过程中使用
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{})
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 2.2 连接池
- GORM 使用 database/sql (opens new window) 维护连接池
package mysql
import (
"database/sql"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DBConn *gorm.DB
func Init() {
//dsn := "root:1@tcp(127.0.0.1:3306)/test_db?charset=utf8mb4&parseTime=True&loc=Local"
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
"root", "1", "127.0.0.1:3306", "test_db")
// GORM 使用 database/sql 维护连接池
sqlDB, err := sql.Open("mysql", dsn)
if err != nil {
panic(fmt.Sprintf("sql.Open err, \v", err))
}
// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)
// SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(100)
gormDB, err := gorm.Open(mysql.New(mysql.Config{
Conn: sqlDB,
}), &gorm.Config{
//禁用外键生成
DisableForeignKeyConstraintWhenMigrating: true,
//Logger: newLogger, //重新修改数据库日志配置
})
if err != nil {
panic(fmt.Sprintf("链接数据库失败\v", err))
}
DBConn = gormDB
}
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
29
30
31
32
33
34
35
36
37
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
29
30
31
32
33
34
35
36
37
上次更新: 2024/3/13 15:35:10