公司用的还是 v1.x版本,业务场景是先根据条件删除一条记录,同时写入一条新的。 要保证两者要么同时执行成功,要么都不执行。本地demo记录一下:
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;
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这条会被删掉,同时生成一行新的记录
}