golang学习笔记(14)-gorm事务

gorm事务

准备工作

建立数据库连接

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
)

var db *gorm.DB

func OpenDB() {
	dsn := "root:adss123@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True&loc=Local"
	res, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	db = res
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("成功:%v\n", db)
}

建立一个表

type TransactionTest struct {
	gorm.Model
	Name string
}

禁用默认事务

为了确保数据一致性,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)

事务

要在事务中执行一系列操作,一般流程如下:

db.Transaction(func(tx *gorm.DB) error {
  // 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
  if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
    // 返回任何错误都会回滚事务
    return err
  }

  if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
    return err
  }

  // 返回 nil 提交事务
  return nil
})

实验案例如下
正常创建一条记录

func InsertTra() {
	OpenDB()
	t := &TransactionTest{Name: "test1"}
	db.Transaction(func(tx *gorm.DB) error {
		tx.Create(t)
		return nil
	})
}

在这里插入图片描述
当Transaction返回值为error时,事务会作废。但是Transaction函数内命令都会执行一遍

func InsertTra() {
	OpenDB()
	t := &TransactionTest{Name: "test1"}
	t2 := &TransactionTest{Name: "test2"}
	db.Transaction(func(tx *gorm.DB) error {
		tx.Create(t)
		tx.Create(t2)
		fmt.Println("函数执行过")
		return errors.New("失败测试...")
	})
}

在这里插入图片描述
事务没执行
在这里插入图片描述
但是函数命令都过了一遍。

嵌套事务

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

实验案例如下

func InsertTra() {
	OpenDB()
	t := &TransactionTest{Name: "test1"}
	t2 := &TransactionTest{Name: "test2"}
	t3 := &TransactionTest{Name: "test3"}
	db.Transaction(func(tx *gorm.DB) error {
		tx.Create(t)
		tx.Create(t2)
		tx.Transaction(func(tx *gorm.DB) error {
			tx.Create(t3)
			return errors.New("失败测试")
		})
		return nil
	})
}

函数目的是,在创建t与t2记录的事务下嵌套一个创建t3的事务。
执行结果为:
在这里插入图片描述
发现t3没被创建,发现被嵌套的事务是否执行,不影响外层事务的执行。而且发现事务的回滚是会影响自增长的字段的。被回滚的记录还是会导致自增长字段改变。

手动事务

Gorm 支持直接调用事务控制方法(commit、rollback),例如:

// 开始事务
tx := db.Begin()

// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
tx.Create(...)

// ...

// 遇到错误时回滚事务
tx.Rollback()

// 否则,提交事务
tx.Commit()

实验案例如下
现在以flag的正假来模拟error

func InsertTra() {
	OpenDB()
	flag := true
	t := &TransactionTest{Name: "test1"}
	t2 := &TransactionTest{Name: "test2"}
	t3 := &TransactionTest{Name: "test3"}
	tx := db.Begin()
	tx.Create(t)
	tx.Create(t2)
	tx.Create(t3)
	if flag {
		tx.Rollback()
	} else {
		tx.Commit()
	}

}

当flag为真的时候,事务回滚,flag为假的时候事务执行。
现在测试tx的生命周期

func InsertTra() {
	OpenDB()
	flag := true
	t := &TransactionTest{Name: "test1"}
	t2 := &TransactionTest{Name: "test2"}
	t3 := &TransactionTest{Name: "test3"}
	tx := db.Begin()
	tx.Create(t)
	tx.Create(t2)

	if flag {
		tx.Rollback()
	} else {
		tx.Commit()
	}
	tx.Create(t3)
}

在这里插入图片描述
发现tx的生命周期从begin()开始,到Rollback(),Commit()结束。

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

实验代码如下

func InsertTra() {
	OpenDB()
	t := &TransactionTest{Name: "test1"}
	t2 := &TransactionTest{Name: "test2"}
	t3 := &TransactionTest{Name: "test3"}
	tx := db.Begin()
	tx.Create(t)
	tx.Create(t2)
	tx.SavePoint("sp1")
	tx.Create(t3)
	tx.RollbackTo("sp1")
	tx.Commit()
}

在这里插入图片描述
发现只创建了t和t2,说明 SavePoint、RollbackTo操作成功,也就是间接实现了上文的嵌套事务的功能。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
GoLang学习笔记主要包括以下几个方面: 1. 语法规则:Go语言要求按照语法规则编写代码,例如变量声明、函数定义、控制结构等。如果程序中违反了语法规则,编译器会报错。 2. 注释:Go语言中的注释有两种形式,分别是行注释和块注释。行注释使用`//`开头,块注释使用`/*`开头,`*/`结尾。注释可以提高代码的可读性。 3. 规范代码的使用:包括正确的缩进和空白、注释风格、运算符两边加空格等。同时,Go语言的代码风格推荐使用行注释进行注释整个方法和语句。 4. 常用数据结构:如数组、切片、字符串、映射(map)等。可以使用for range遍历这些数据结构。 5. 循环结构:Go语言支持常见的循环结构,如for循环、while循环等。 6. 函数:Go语言中的函数使用`func`关键字定义,可以有参数和返回值。函数可以提高代码的重用性。 7. 指针:Go语言中的指针是一种特殊的变量,它存储的是另一个变量的内存地址。指针可以实现动态内存分配和引用类型。 8. 并发编程:Go语言提供了goroutine和channel两个并发编程的基本单位,可以方便地实现多线程和高并发程序。 9. 标准库:Go语言提供了丰富的标准库,涵盖了网络编程、文件操作、加密解密等多个领域,可以帮助开发者快速实现各种功能。 10. 错误处理:Go语言中的错误处理使用`defer`和`panic`两个关键字实现,可以有效地处理程序运行过程中出现的错误。 通过以上内容的学习,可以掌握Go语言的基本语法和编程思想,为进一步学习和应用Go语言打下坚实的基础。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Golang学习笔记](https://blog.csdn.net/weixin_52310067/article/details/129467041)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [golang学习笔记](https://blog.csdn.net/qq_44336275/article/details/111143767)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值