GORM中使用事务

公司用的还是 v1.x版本,业务场景是先根据条件删除一条记录,同时写入一条新的。 要保证两者要么同时执行成功,要么都不执行。本地demo记录一下:

1
2
3
4
5
6
7
8
9
10
create table shuang.student
(
id int auto_increment
primary key,
name varchar(128) not null,
age int not null,
id_card varchar(128) not null,
last_update date not null
)
charset = utf8mb4;

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

package main

import (
"fmt"
"github.com/davecgh/go-spew/spew"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
"os"
"time"
)

type Student struct {
ID int64 `gorm:"column:id" db:"id" json:"id" form:"id"`
Name string `gorm:"column:name" db:"name" json:"name" form:"name"`
Age int64 `gorm:"column:age" db:"age" json:"age" form:"age"`
IdCard string `gorm:"column:id_card" db:"id_card" json:"id_card" form:"id_card"`
LastUpdate time.Time `gorm:"column:last_update" db:"last_update" json:"last_update" form:"last_update"`
}

func (Student) TableName() string {
return "student"
}

func main() {
dsn := "root:12345678@tcp(127.0.0.1:3306)/shuang?charset=utf8mb4&parseTime=True&loc=Local"

db, err := gorm.Open("mysql", dsn)

if err != nil {
fmt.Fprintln(os.Stderr, "connect db addr :", dsn, "err :", err)
panic(fmt.Sprintf("连接数据库失败: %s", err))
}

db.LogMode(true) // 是否打印每条sql

db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(200)
db.DB().SetConnMaxLifetime(10 * time.Second)

if err != nil {
panic("failed to connect database")
}

// 用于构造数据
//stu0 := &Student{Name: "爽哥测试333", Age: 200, IdCard: "qwert", LastUpdate: time.Now()}
//// 插入新数据
//errC := db.Create(stu0).Error
//if errC != nil {
// fmt.Printf("插入新纪录错误 err:%#v\n", errC)
//}

var stu Student
db.Table("student").Where("id=?", 36).First(&stu)

spew.Dump("取出的记录为:", stu)

errT := db.Transaction(func(tx *gorm.DB) error {
// 先删
fmt.Println("要删的id是:", stu.ID)

// errD := tx.Where("name=? ", stu.Name).Delete(&stu).Error
// 最好传入一个空的&Student{}
// Limit(1)限制最多只删除一行,需要加在Delete()的前面
errD := tx.Where("name=? ", stu.Name).Limit(1).Delete(&Student{}).Error

if errD != nil {
fmt.Printf("删除纪录错误 err:%#v\n", errD)
return errD
}

// 再故意写入失败(ID冲突),则上面的删除操作需要回滚,原来的记录不能被删掉
stu2 := &Student{Name: stu.Name, Age: stu.Age, IdCard: stu.IdCard, LastUpdate: time.Now(), ID: 37}

errC := tx.Create(stu2).Error

if errC != nil {
fmt.Printf("写入新纪录错误 err:%#v\n", errC)
return errC
}

return nil

})

fmt.Println("事务执行的errT为:", errT)

// 事务生效的标准就是36这条记录不能真的被删掉。执行后和执行前记录完全一样

// 将上面stu2从的ID:37 去掉,再执行代码,则36这条会被删掉,同时生成一行新的记录

}



GORM-事务

如何让gorm输出执行的sql

文章目录