MST

星途 面试题库

面试题:Go语言defer、panic与recover在复杂业务中的应用

假设你正在开发一个处理数据库事务的Go程序,在事务处理过程中可能会出现各种错误。请使用defer、panic和recover机制,设计一个函数来处理事务,要求在发生错误时能够回滚事务,并以合理的方式记录和报告错误。
12.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
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)
    }
}

在上述代码中:

  1. executeTransaction函数接受一个数据库连接db和一个处理事务的函数f
  2. 首先开启一个事务tx
  3. 使用defer定义一个匿名函数,在函数结束时执行。
    • 如果发生panic,捕获panic,记录错误,回滚事务,然后重新panic以便上层调用者知晓。
    • 如果函数f返回错误,记录错误并回滚事务。
    • 如果没有错误,提交事务,如果提交事务过程中发生错误,也记录错误。
  4. 调用f(tx)执行具体的事务操作,并返回其错误。

main函数中演示了如何调用executeTransaction函数来执行数据库事务操作。