面试题答案
一键面试package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/lib/pq" // 以PostgreSQL为例,实际可替换为对应数据库驱动
)
func executeTransaction(db *sql.DB, f func(tx *sql.Tx) error) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer func() {
if r := recover(); r != nil {
// 捕获panic
err = fmt.Errorf("panic occurred: %v", r)
log.Println(err)
tx.Rollback()
panic(r)
} else if err != nil {
// 捕获函数f返回的错误
log.Println("transaction error:", err)
tx.Rollback()
} else {
// 没有错误,提交事务
err = tx.Commit()
if err != nil {
log.Println("commit error:", err)
}
}
}()
err = f(tx)
return err
}
你可以这样调用这个函数:
func main() {
// 初始化数据库连接
db, err := sql.Open("postgres", "user=postgres dbname=mydb sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = executeTransaction(db, func(tx *sql.Tx) error {
// 执行具体的数据库操作
_, err := tx.Exec("INSERT INTO your_table (column1, column2) VALUES ($1, $2)", "value1", "value2")
return err
})
if err != nil {
log.Println("overall error:", err)
}
}
在上述代码中:
executeTransaction
函数接受一个数据库连接db
和一个处理事务的函数f
。- 首先开启一个事务
tx
。 - 使用
defer
定义一个匿名函数,在函数结束时执行。- 如果发生
panic
,捕获panic
,记录错误,回滚事务,然后重新panic
以便上层调用者知晓。 - 如果函数
f
返回错误,记录错误并回滚事务。 - 如果没有错误,提交事务,如果提交事务过程中发生错误,也记录错误。
- 如果发生
- 调用
f(tx)
执行具体的事务操作,并返回其错误。
在main
函数中演示了如何调用executeTransaction
函数来执行数据库事务操作。