从GORM里学习到的panic处理方式

今天在博客的评论里,有童鞋提醒我,GORM里也有简化事务处理的帮助函数。源码如下:

// Transaction start a transaction as a block, return error will rollback, otherwise to commit.
func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error) {
	panicked := true

	if committer, ok := db.Statement.ConnPool.(TxCommitter); ok && committer != nil {
		// nested transaction
		db.SavePoint(fmt.Sprintf("sp%p", fc))
		defer func() {
			// Make sure to rollback when panic, Block error or Commit error
			if panicked || err != nil {
				db.RollbackTo(fmt.Sprintf("sp%p", fc))
			}
		}()

		err = fc(db.Session(&Session{WithConditions: true}))
	} else {
		tx := db.Begin(opts...)

		defer func() {
			// Make sure to rollback when panic, Block error or Commit error
			if panicked || err != nil {
				tx.Rollback()
			}
		}()

		err = fc(tx)

		if err == nil {
			err = tx.Commit().Error
		}
	}

	panicked = false
	return
}

思路和 我的 差不多。

有两个不同,第一,在获取了committer 的时候,会优先选择使用savepoint这个特性,相当于事务里的子事务。

第二,处理panic的方式,这一点值得学习。首先在函数的入口处设置变量:panicked := true,在 defer 函数中判断是否panic了,从而进行相应处理:

		defer func() {
			// Make sure to rollback when panic, Block error or Commit error
			if panicked || err != nil {
				db.RollbackTo(fmt.Sprintf("sp%p", fc))
			}
		}()

那么什么情况下,不会执行呢?当然就是执行到最后的时候,执行了 panicked = false 这一行代码之后。

这样就成功避免了使用 recover 来判断是否发生了异常。不过也因此,无法在这一层捕捉 panic 了。


ref:


微信公众号
关注公众号,获得及时更新

更多文章
  • 设计一个路由
  • Go语言性能优化实战
  • 那些年开发的时候踩过的坑
  • (关系型)数据库优化总结
  • 动态规划民科教程
  • Golang 分布式异步任务队列 Machinery 教程
  • 使用geohash完成地理距离计算
  • 2018年就要到了,这一年都做了什么呢?
  • 算法导论阅读笔记 --- 排序算法
  • Git HTTPS 如何保存密码
  • 短链系统的实现
  • 程序员修炼之道 阅读笔记
  • Python开发实践经验
  • Golang实现平滑重启(优雅重启)
  • traefik 教程