前言

go中操作数据库一般使用gorm框架进行,而较少用原生的datebase/sql包。标准库的datebase/sql包需要手写sql,对于简单的sql操作来说过于繁琐,因此平时开发更倾向于使用gorm。而说到数据库操作,就离不开事务管理,gorm支持事务管理,并且非常灵活、简单

介绍

开启事务

1
2
3
4
tx := db.Begin()
if tx.Error != nil {
return tx.Error
}

当发生错误时,回滚事务

1
2
3
if err != nil {
tx.Rollback()
}

提交事务

1
2
3
4
if err := tx.Commit().Error;err != nil {
// 提交事务发生异常
tx.Rollback()
}

事务失效的情况

由于每次gorm操作数据库时,都会向连接池获取一个连接,这些连接不共享一个事务,因此在涉及多张表操作时,如果想由同一个事务控制,则需要使用由db.Begin()开启事务时返回的tx对象

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
func (s *TaskService) AddTeamTask(task models.Task) error {
// 开启事务
tx := s.teamTaskRepository.Db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()

// 向任务表写数据
if err := s.taskRepository.Create(&task); err != nil {
tx.Rollback()
return err
}

teamTask := models.TeamTask{
TaskId: task.Id,
UserId: task.UserId,
Status: 0,
}

// 向任务关系表写数据
if err := s.teamTaskRepository.Create(&teamTask); err != nil {
tx.Rollback()
return err
}

// 提交事务
return tx.Commit().Error
}

两张表插入数据时,都在使用自己的数据库连接,并没有用到tx,不共享同一个事务,此时即使tx.Rollback()也是无效的回滚。

直接操作

更加简单快速、适合快速开发

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
func (s *TaskService) AddTeamTask(task models.Task) error {
// 开启事务
tx := s.teamTaskRepository.Db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()

// 向任务表写数据
if err := tx.Create(&task); err != nil {
tx.Rollback()
return err
}

teamTask := models.TeamTask{
TaskId: task.Id,
UserId: task.UserId,
Status: 0,
}

// 向任务关系表写数据
if err := tx.Create(&teamTask); 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
26
27
28
29
30
func (s *TaskService) AddTeamTask(task models.Task) error {
// 开启事务
tx := s.teamTaskRepository.Db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()

// 向任务表写数据
if err := s.taskRepository.Create(&task,tx); err != nil {
tx.Rollback()
return err
}

teamTask := models.TeamTask{
TaskId: task.Id,
UserId: task.UserId,
Status: 0,
}

// 向任务关系表写数据
if err := s.teamTaskRepository.Create(&teamTask,tx); err != nil {
tx.Rollback()
return err
}

// 提交事务
return tx.Commit().Error
}

在不需要事务管理时,只需要传入nil即可。