recover只能在defer中捕获当前goroutine的panic,需写成defer func(){if r:=recover();r!=nil{}}();子goroutine panic需各自recover;返回值需类型断言;事务回滚须手动实现且保证幂等;recover后应立即返回而非继续业务逻辑。
panic 之后如何用 recover 捕获并恢复执行
recover 只能在 defer 函数中生效,且仅对当前 goroutine 的 panic 有效。它不是“全局错误处理器”,也不能在任意位置调用就起作用。
常见错误是把 recover() 写在普通函数里,或者没包在 defer 中,结果返回 nil,程序仍崩溃。
- 必须写成
defer func() { if r := recover(); r != nil { /* 处理 */ } }() - 如果 panic 发生在子 goroutine,主 goroutine 的 recover 完全无效,需在子 goroutine 内部单独 defer+recover
-
recover()返回的是interface{},通常要类型断言,比如r.(error)或r.(string),否则可能 panic 二次
事务性操作失败时怎么安全回滚(如 DB + 文件写入)
Go 标准库不提供内置事务抽象,回滚必须手动编码。关键不是“有没有 rollback 方法”,而是“状态是否可逆”和“回滚逻辑是否幂等”。
例如:先写数据库再写本地文件,若文件写入失败,仅靠 recover 无法撤回已提交的 DB 事务——必须用显式事务控制 + 补偿逻辑。
- DB 层用
tx, err := db.Begin(),出错时调用tx.Rollback();成功才tx.Commit() - 涉及多系统(如 DB + Redis + 文件),推荐“正向执行 + 补偿任务”模式:记录操作日志(
op_log表),失败后异步重试或反向操作 - 避免在 defer 中做回滚(如
defer tx.Rollback()),除非你确定一定需要回滚——它会覆盖Commit()调用
recover 后能否继续正常处理请求(HTTP handler 场景)
可以,但要注意:recover 只阻止 panic 传播,不修复已损坏的状态。HTTP handler 中 recover 后返回 500 是安全的,但直接复用被 panic 中断的 struct 字段可能引发后续 panic。