You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Go语言中模拟try/catch,且保留数据库错误上下文信息?

在Go中实现带数据库文件信息的批量SQL执行错误处理

场景回顾

Java里可以用try/catch批量执行SQL,捕获异常时直接带上数据库文件的信息,代码简洁还能定位问题:

db.Attach(dbFile)
try {
   db.Exec(sql1);
   db.Exec(sql2);
   db.Exec(sql3);
} catch (SQLException e) {
    throw new Error("sql error in executing " + dbFile + " ", e);
}

但在Go里,要是逐个判断db.Exec的错误,代码会变得很冗余:

db.Attach(dbFile)
var err error
if err = db.Exec(sql1); err != nil {
   log.Panic(fmt.Sprintf("error in attaching db %s error : %s", dbFile, err))
}
if err = db.Exec(sql2); err != nil {
   log.Panic(fmt.Sprintf("error in attaching db %s error : %s", dbFile, err))
}
if err = db.Exec(sql3); err != nil {
   log.Panic(fmt.Sprintf("error in attaching db %s error : %s", dbFile, err))
}

用db.MustExec虽然能简化代码,但没法在错误信息里带上关联的数据库文件:

db.Attach(dbFile)
db.MustExec(sql1)
db.MustExec(sql2)
db.MustExec(sql3)

下面给几个不冗余、也不用循环SQL切片的解决办法:

解决方案

1. 自定义带数据库标识的MustExec方法

要是你的db是自定义结构体,直接给它加个专属的MustExec方法,把dbFile绑定进去:

type MyDB struct {
    *sql.DB // 假设原数据库实例是sql.DB
    dbFile string
}

func (m *MyDB) MustExec(query string, args ...interface{}) {
    _, err := m.Exec(query, args...)
    if err != nil {
        log.Panicf("执行数据库%s出错: %v", m.dbFile, err)
    }
}

// 用的时候这样写
db := &MyDB{DB: originalDB, dbFile: dbFile}
db.Attach(dbFile)
db.MustExec(sql1)
db.MustExec(sql2)
db.MustExec(sql3)

2. 用闭包临时包装

不想改原DB结构体的话,用闭包快速封装一个带dbFile的执行函数就行,主代码依然简洁:

db.Attach(dbFile)

// 封装一个带dbFile的mustExec
mustExec := func(query string, args ...interface{}) {
    _, err := db.Exec(query, args...)
    if err != nil {
        log.Panicf("执行数据库%s出错: %v", dbFile, err)
    }
}

// 直接调用就行
mustExec(sql1)
mustExec(sql2)
mustExec(sql3)

3. 用defer+recover模拟try/catch

要是想更贴近Java的try/catch模式,用Go的defer+recover机制,把批量执行逻辑包在一个函数里,捕获panic后加上dbFile信息:

func execWithDB(db *sql.DB, dbFile string, sqls ...string) {
    defer func() {
        if r := recover(); r != nil {
            // 把捕获到的错误重新包装,带上dbFile
            err, ok := r.(error)
            if !ok {
                err = fmt.Errorf("%v", r)
            }
            log.Panicf("数据库%s执行SQL出错: %v", dbFile, err)
        }
    }()

    // 这里虽然用了循环,但主逻辑里不用写,也不算冗余
    for _, sql := range sqls {
        db.MustExec(sql)
    }
}

// 使用方式
db.Attach(dbFile)
execWithDB(db, dbFile, sql1, sql2, sql3)

内容的提问来源于stack exchange,提问作者Demeter P. Chen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 19:27:28