gorm的事务管理
前言
go中操作数据库一般使用gorm框架进行,而较少用原生的datebase/sql包。标准库的datebase/sql包需要手写sql,对于简单的sql操作来说过于繁琐,因此平时开发更倾向于使用gorm。而说到数据库操作,就离不开事务管理,gorm支持事务管理,并且非常灵活、简单
介绍
开启事务
tx := db.Begin()
if tx.Error != nil {
return tx.Error
}
当发生错误时,回滚事务
if err != nil {
tx.Rollback()
}
提交事务
if err := tx.Commit().Error;err != nil {
// 提交事务发生异常
tx.Rollback()
}
事务失效的情况
由于每次gorm操作数据库时,都会向连接池获取一个连接,这些连接不共享一个事务,因此在涉及多张表操作时,如果想由同一个事务控制,则需要使用由db.Begin()开启事务时返回的tx对象
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()也是无效的回滚。
直接操作
更加简单快速、适合快速开发
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
}
数据库层支持传入操作指针
更加灵活,而且保留了数据库操作的封装性。同时也保持了代码的可读性,可根据调用的对象和函数快速判断在向哪张数据库表进行什么操作。
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即可。