Golang中Sqlx事务处理指南
Golang中Sqlx事务处理指南 你好,
我正在使用 sqlx 向具有外键关系的 MySQL 数据库表中插入多行数据。能否请您审阅下面的代码?我不太确定应该在何处使用回滚。这是一个好的做法吗?
tx, err := db.Begin()
if err != nil {
return
}
r, err := tx.Exec("INSERT INTO licenses ...")
if err != nil {
tx.Rollback() // 我应该在这里使用回滚吗?
return
}
licenseId, _ := r.LastInsertId()
r, err = tx.Exec("INSERT INTO companies ...", licenseId, ...)
if err != nil {
tx.Rollback()
return
}
companyId, _ := r.LastInsertId()
r, err = tx.Exec("INSERT INTO users ...", companyId, ...)
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
if err != nil {
tx.Rollback() // 我应该在这里使用回滚吗?
return
}
此致敬礼…
更多关于Golang中Sqlx事务处理指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html
6 回复
为提交和回滚编写defer函数
你好,欢迎,
我不知道这个问题的答案 😊
如果三条 INSERT 语句必须全部成功,或者都不产生任何效果,那么必须在每次出现错误时回滚事务,正如您所做的那样。
ermanimer:
LastInsertId
如果你使用的是UUID而不是ID会怎样?因为 r.LastInsertId() 返回的是 int64 类型。
func main() {
fmt.Println("hello world")
}
这是一个正确的事务处理模式,但可以进一步优化。以下是改进后的代码示例:
tx, err := db.Begin()
if err != nil {
return err
}
defer func() {
if p := recover(); p != nil {
tx.Rollback()
panic(p)
} else if err != nil {
tx.Rollback()
} else {
err = tx.Commit()
if err != nil {
tx.Rollback()
}
}
}()
r, err := tx.Exec("INSERT INTO licenses (name) VALUES (?)", "license1")
if err != nil {
return err
}
licenseId, err := r.LastInsertId()
if err != nil {
return err
}
r, err = tx.Exec("INSERT INTO companies (license_id, name) VALUES (?, ?)", licenseId, "company1")
if err != nil {
return err
}
companyId, err := r.LastInsertId()
if err != nil {
return err
}
_, err = tx.Exec("INSERT INTO users (company_id, name) VALUES (?, ?)", companyId, "user1")
if err != nil {
return err
}
return nil
关键改进:
- 使用
defer确保事务始终被正确处理 - 处理
LastInsertId()的错误 - 添加 panic 恢复机制
- 统一错误处理路径
对于 sqlx 的特定用法,可以使用命名参数:
type License struct {
Name string `db:"name"`
}
type Company struct {
LicenseID int64 `db:"license_id"`
Name string `db:"name"`
}
type User struct {
CompanyID int64 `db:"company_id"`
Name string `db:"name"`
}
tx, err := db.Beginx()
if err != nil {
return err
}
defer func() {
if err != nil {
tx.Rollback()
} else {
err = tx.Commit()
}
}()
license := License{Name: "license1"}
result, err := tx.NamedExec("INSERT INTO licenses (name) VALUES (:name)", license)
if err != nil {
return err
}
licenseId, err := result.LastInsertId()
if err != nil {
return err
}
company := Company{LicenseID: licenseId, Name: "company1"}
result, err = tx.NamedExec("INSERT INTO companies (license_id, name) VALUES (:license_id, :name)", company)
if err != nil {
return err
}
companyId, err := result.LastInsertId()
if err != nil {
return err
}
user := User{CompanyID: companyId, Name: "user1"}
_, err = tx.NamedExec("INSERT INTO users (company_id, name) VALUES (:company_id, :name)", user)
if err != nil {
return err
}
return nil
这种模式确保:
- 任何错误都会触发回滚
- Commit 失败也会触发回滚
- 代码更简洁,错误处理更一致
- 使用 sqlx 的特性提高可读性

