🌙 1.什么是事务?
事务是指一组数据库操作,这些操作要么全部执行成功,要么全部不执行。事务通常用于处理复杂的数据操作,以确保数据的完整性和一致性。
在事务中,可以将多个数据库操作作为一个整体来执行,如果其中任何一个操作失败,整个事务将会回滚到起始状态,所有操作都将被撤销,以保证数据的一致性。
事务具有四个基本特性,通常称为ACID特性:
原子性(Atomicity):事务是一个不可分割的操作单元,要么全部执行成功,要么全部不执行。
一致性(Consistency):事务执行前后,数据库的状态必须保持一致。如果事务执行失败,所有的修改都必须回滚,以保证数据的一致性。
隔离性(Isolation):事务的执行应该与其他事务相互隔离,每个事务都应该认为自己是唯一在数据库中执行的事务。
持久性(Durability):事务一旦提交,对数据库的修改就是永久性的,即使发生系统故障也不会丢失。
ACID特性是保证事务正确执行的基础,这些特性确保了事务的正确性、可靠性和一致性。
🌙 2.gorm 事务 (opens new window)
// 开启事务
tx := DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 事务操作
if err := tx.Create(&user).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Model(&user).Update("age", 18).Error; err != nil {
tx.Rollback()
return err
}
// 提交事务
return tx.Commit().Error
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 禁用默认事务 为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升。
🌙 3.gorm Session (opens new window)
为了避免公用DB导致的一些问题, GORM 提供了会话模式,通过新建Session 的形式,将DB操作分离,互不影响。
- Session 配置项
type Session struct {
DryRun bool // 生成SQL但不执行
PrepareStmt bool // 预编译模式
NewDB bool // 新DB不带之前的条件
Initialized bool // 初始化新的DB
SkipHooks bool // 跳过钩子函数
SkipDefaultTransaction bool // 禁用默认事务
DisableNestedTransaction bool // 禁用嵌套事务
AllowGlobalUpdate bool // 允许不带条件更新
FullSaveAssociations bool // 允许更新关联数据
QueryFields bool // 比如:select * 查询会显示具体的字段,
Context context.Context // 上下文
Logger logger.Interface // 日志
NowFunc func() time.Time // 获取当前时间函数
CreateBatchSize int // 允许改变 GORM 获取当前时间的实现
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- 禁用默认事务
SkiDefaultTransaction: true
,大概可以提升30%性能
tx := DB.Session(&Session{SkiDefaultTransaction: true})
tx.First(&user, 1)
tx.Find(&users)
tx.Model(&user).Update("Age", 18)
2
3
4
- 使用预编译
PrepareStmt: true
,在执行任何 SQL 时都会创建一个 prepared statement 并将其缓存,以提高后续效率。
// 会话模式
tx := DB.Session(&Session{PrepareStmt: true})
tx.First(&user, 1)
tx.Find(&users)
tx.Model(&user).Update("Age", 18)
// 获取预编译的系统申明
stmtManager, ok := tx.ConnPool.(*PreparedStmtDB)
// 关闭当前会话的预编译模式
stmtManager.Close()
2
3
4
5
6
7
8
9
10
11
- GORM DB默认是协程安全的,如果使用初始化参数
Initialized: true
,则DB不再协程安全。
tx := DB.Session(&Session{Initialized: true})
- 可以设置context:
Context: timeoutCtx
,是后续操作带上context
timeoutCtx, _ := context.WithTimeout(context.Background(), time.Second)
tx := DB.Session(&Session{Context: timeoutCtx})
tx.First(&user, 1) // 带有context timeoutCtx 的查询操作
tx.Model(&user).Update("Age", 18) // 带有context timeoutCtx 的更新操作
2
3
4
5
- 开启事务
// 禁用了默认事务,提升了性能。
tx := DB.Session(&gorm.Session{SkiDefaultTransaction: true}).Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 事务操作
if err := tx.Create(&user).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Model(&user).Update("age", 18).Error; err != nil {
tx.Rollback()
return err
}
// 提交事务
return tx.Commit().Error
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
🌙 4.gorm Hook (opens new window)
GORM Hook是一种在执行数据库操作前或后自动执行的函数,可以用于在执行操作前或后执行某些操作,例如验证数据、修改数据等。
GORM提供了多种类型的Hook,包括创建、更新、删除、查询等。Hook可以在模型中定义,也可以在全局范围内定义。以下是一个示例,展示了如何在模型中定义一个Hook:
type User struct {
gorm.Model
Name string
Age int
}
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
// 在创建之前执行的操作
return
}
func (u *User) AfterCreate(tx *gorm.DB) (err error) {
// 在创建之后执行的操作
return
}
// 在全局范围内定义Hook
DB.Callback().Create().Before("gorm:create").Do(func(tx *gorm.DB) {
// 在创建之前执行的操作
})
DB.Callback().Create().After("gorm:create").Do(func(tx *gorm.DB) {
// 在创建之后执行的操作
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
在上面的示例中,我们定义了一个名为User的模型,并在其中定义了两个Hook:BeforeCreate和AfterCreate。这些Hook将在创建User记录之前和之后执行。我们还展示了如何在全局范围内定义Hook,这些Hook将在所有创建操作之前和之后执行。
具体而言,GORM提供了以下类型的Hook:
- 创建操作:
// begin transaction
BeforeSave
BeforeCreate
// save before associations
// insert into database
// save after associations
AfterCreate
AfterSave
// commit or rollback transaction
2
3
4
5
6
7
8
9
- 更新操作:
// begin transaction
BeforeSave
BeforeUpdate
// save before associations
// update database
// save after associations
AfterUpdate
AfterSave
// commit or rollback transaction
2
3
4
5
6
7
8
9
10
- 删除操作:
// begin transaction
BeforeDelete
// delete from database
AfterDelete
// commit or rollback transaction
2
3
4
5
6
- 查询操作:
// load data from database
// Preloading (eager loading)
AfterFind
2
3