在 Go 语言中,虽然没有像 Java 中的 try-catch
语句那样直接的语法结构,但你可以使用 defer
关键字来简化事务的回滚逻辑。通过 defer
,你可以在函数退出时自动执行回滚操作,从而避免在每个可能出错的地方都写 tx.Rollback()
。
以下是一个示例,展示了如何使用 defer
来简化事务处理:
package main
import (
"database/sql"
"fmt"
"log"
"os"
_ "github.com/go-sql-driver/mysql"
)
func main() {
// 数据库连接字符串
dsn := "username:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
// 打开数据库连接
db, err := sql.Open("mysql", dsn)
if err != nil {
log.Fatalf("Error opening database: %v", err)
}
defer db.Close()
// 开始事务
tx, err := db.Begin()
if err != nil {
log.Fatalf("Error beginning transaction: %v", err)
}
// 使用 defer 确保在函数退出时回滚事务
defer func() {
if err != nil {
tx.Rollback()
log.Printf("Transaction rolled back: %v", err)
}
}()
// 执行一些 SQL 语句
_, err = tx.Exec("INSERT INTO users (name, email) VALUES (?, ?)", "Alice", "alice@example.com")
if err != nil {
return // 如果有错误,直接返回,defer 会自动回滚事务
}
_, err = tx.Exec("UPDATE accounts SET balance = balance - 100 WHERE user_id = ?", 1)
if err != nil {
return // 如果有错误,直接返回,defer 会自动回滚事务
}
// 提交事务
err = tx.Commit()
if err != nil {
log.Fatalf("Error committing transaction: %v", err)
}
// 清除错误标志,防止 defer 回滚
err = nil
fmt.Println("Transaction committed successfully!")
}
关键点解释
- 打开数据库连接:
db, err := sql.Open("mysql", dsn)
if err != nil {
log.Fatalf("Error opening database: %v", err)
}
defer db.Close()
- 开始事务:
tx, err := db.Begin()
if err != nil {
log.Fatalf("Error beginning transaction: %v", err)
}
- 使用
defer
确保回滚:
defer func() {
if err != nil {
tx.Rollback()
log.Printf("Transaction rolled back: %v", err)
}
}()
这个 defer
函数会在 main
函数退出时自动执行。如果 err
不为 nil
,则会回滚事务并记录错误信息。
- 执行 SQL 语句:
_, err = tx.Exec("INSERT INTO users (name, email) VALUES (?, ?)", "Alice", "alice@example.com")
if err != nil {
return // 如果有错误,直接返回,defer 会自动回滚事务
}
_, err = tx.Exec("UPDATE accounts SET balance = balance - 100 WHERE user_id = ?", 1)
if err != nil {
return // 如果有错误,直接返回,defer 会自动回滚事务
}
- 提交事务:
err = tx.Commit()
if err != nil {
log.Fatalf("Error committing transaction: %v", err)
}
- 清除错误标志:
err = nil
在成功提交事务后,将 err
设置为 nil
,以防止 defer
函数中的回滚操作被执行。
通过这种方式,你只需要在一个地方写 tx.Rollback()
,并且可以确保在任何错误发生时事务都会被回滚。这样不仅代码更简洁,也减少了重复代码和潜在的错误。
Was this helpful?
0 / 0