事务
func Transaction(db *gorm.DB) error {
// 为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升。
db = db.Session(&gorm.Session{SkipDefaultTransaction: true}) //临时禁用默认事务
tx := db.Begin() // 开始事务
defer func() {
if err := recover(); err != nil {
tx.Rollback() //手动回滚
}
}()
if err := tx.Error; err != nil {
return err
}
user := User{UserId: rand.IntN(100000), Degree: "本科", Gender: "男", City: "上海"}
fmt.Printf("uid=%d\n", user.UserId)
if err := tx.Create(&user).Error; err != nil {
tx.Rollback() //手动回滚
fmt.Println("第一次Create回滚")
return err
}
user.Id = 0
if err := tx.Create(&user).Error; err != nil { //第二次会失败,因为uid重复了
tx.Rollback() //手动回滚
fmt.Println("第二次Create回滚")
return err
}
return tx.Commit().Error //提交事务。Commit和Rollback只能执行一个,且只能执行一次
}
执行原生sql
// 执行原生的select语句
func RawSelect(db *gorm.DB) {
var users []User
db.Raw("select id,uid,city from user where id>? and uid>? limit 3", 2, 4).Scan(&users)
for _, user := range users {
fmt.Printf("uid %d city %s\n", user.UserId, user.City)
}
fmt.Println()
rows, err := db.Raw("select id,uid,city from user where id>? and uid>? limit 3", 2, 4).Rows()
if err == nil {
defer rows.Close()
var id, uid int
var city string
for rows.Next() {
rows.Scan(&id, &uid, &city)
fmt.Printf("uid %d city %s\n", uid, city)
}
}
}
// 执行原生的update、insert、delete语句
func RawExec(db *gorm.DB) {
tx := db.Exec("update user set degree=? where id=?", "大专", 30)
fmt.Printf("更新了%d行\n", tx.RowsAffected)
}
错误处理
var user User
db.First(&user)
tx := db.Create(&user)
if tx.Error != nil {
//获得MySQL错误码,每一个code都对应一种特定的错误
if mysqlErr, ok := tx.Error.(*mysql.MySQLError); ok { //接口的类型断言
switch mysqlErr.Number { //针对不同的错误码,采取不同的处理方案
case 1:
//...
case 2:
//...
default:
fmt.Println("mysql error", "code", mysqlErr.Number, "msg", mysqlErr.Message)
}
} else {
fmt.Printf("err %#v\n", tx.Error)
}
}
或者使用errors.As,跟接口断言是等价的
if tx.Error != nil {
var mysqlErr *mysql.MySQLError //必须是指针,因为是指针实现了error接口
if errors.As(tx.Error, &mysqlErr) {
switch mysqlErr.Number { //针对不同的错误码,采取不同的处理方案
case 1:
//...
case 2:
//...
default:
fmt.Println("mysql error", "code", mysqlErr.Number, "msg", mysqlErr.Message)
}
} else {
fmt.Printf("err %#v\n", tx.Error)
}
}

Comments NOTHING