使用数据库/ sql和驱动程序包和Tx,它不可能检测事务是否已提交或回滚而不尝试另一个事件并接收到错误结果,然后检查错误以确定错误的类型。我希望能够从Tx对象中确定是否已提交。当然,我可以在使用Tx的函数中定义和设置另一个变量,但我有相当多的变量,并且每次都是2次(变量和赋值)。如果需要,我还有一个延迟函数来执行回滚,并且它需要通过bool变量。
在提交或回滚之后将Tx变量设置为零并且GC是否能够恢复任何内存,或者是否否,还是有更好的选择吗?数据库/ sql发送 - 检测提交或回滚
回答
为什么你甚至需要这样做?调用Begin()
的函数也应该调用Commit()
或Rollback()
并返回适当的错误。
例如,这个代码提交或回滚取决于是否会返回一个错误:
func (s Service) DoSomething() (err error) {
tx, err := s.db.Begin()
if err != nil {
return
}
defer func() {
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
}()
if _, err = tx.Exec(...); err != nil {
return
}
if _, err = tx.Exec(...); err != nil {
return
}
// ...
return
}
通知我如何检查error
,看我是否应该提交或回滚。然而,上面的例子并没有处理恐慌。
我不喜欢在每个数据库例程上执行提交/回滚逻辑,所以我通常将它们包装在一个事务处理程序中。沿此线的东西:
func Transact(db *sql.DB, txFunc func(*sql.Tx) error) (err error) {
tx, err := db.Begin()
if err != nil {
return
}
defer func() {
if p := recover(); p != nil {
tx.Rollback()
panic(p) // re-throw panic after Rollback
} else if err != nil {
tx.Rollback()
} else {
err = tx.Commit()
}
}()
err = txFunc(tx)
return err
}
这让我做这件事,而不是:
func (s Service) DoSomething() error {
return Transact(s.db, func (tx *sql.Tx) error {
if _, err := tx.Exec(...); err != nil {
return err
}
if _, err := tx.Exec(...); err != nil {
return err
}
})
}
注意,如果我的事务中的任何恐慌它的自动交易处理程序处理。
在我的实际实施中,我通过一个接口而不是* sql.Tx来防止对Commit()
或Rollback()
的不必要的调用。
这里有一个简单的代码片段演示了如何defer
作品(打印纸4,而不是5):
package main
func test() (i int) {
defer func() {
i = 4
}()
return 5
}
func main() {
println(test())
}
不错的答案!我认为你错过了第二个doSomething()实现结束时的“return nil”。 – splinter123 2015-09-05 15:27:21
卢克,如何以及何时得到评估?根据文档,“err”应该在延迟调用中首次声明时获得它的值。所以对我来说这实际上有点令人困惑,因为推迟使用的“err”的值似乎会改变。 – mirage 2016-10-19 04:11:23
err是通过以下方式声明的:=(冒号等于)。 anon func捕获它。在返回值之前调用延迟。这允许它被设置。当发生恐慌时,它会被恢复,变成错误,然后返回。如果以任何方式发生错误,则会发生回滚。最后,如果没有错误,并且err(当前为零)被设置为Commits返回值以防万一发生错误,则会发生提交。 – Luke 2016-10-20 08:14:21
- 1. 回滚提交的数据
- 2. 应用于数据库的事务更新,无论是否提交或回滚
- 3. JavaScript - 检查后提交到数据库
- 4. 如何在提交后回滚数据库更改?
- 5. SQL Server事务回滚或使用Petapoco提交?
- 6. 在批次结束时检测到不可提交的事务。交易回滚
- 7. 无法提交会话或回滚
- 8. Laravel测试数据库不会回滚
- 9. sql数据库检索数据,等待批准,发送回原来
- 10. 分布式数据库事务是否保证提交/回滚?
- 11. 使用提交发送JavaScript数组到数据库
- 12. AJAX提交表单..数据未发送
- 13. SQL事务回滚并提交
- 14. jQuery + AJAX检索输入提交类型发送的数据
- 15. 如何检测提交可以推送
- 16. BAPI提交和回滚
- 17. 如何回滚或SQL Server提交事务
- 18. NetSuite交易提取到SQL数据库
- 19. 如何回滚,重置或删除Ecto测试数据库?
- 20. 发送纬度和经度,以形成(提交给数据库)
- 21. 发送申请表并提交并插入到数据库中
- 22. 提交的GridView行回数据库
- 23. PDO交易提交而不是回滚
- 24. 从sql数据库发送数据到mysql数据库
- 25. PHP和SQL无法从数据库发送数据
- 26. 通过URL发送到SQL数据库
- 27. 如何在postgres ruby中手动提交或回滚
- 28. 检测SQL数据库改变
- 29. 检测HTML表单提交
- 30. 如何在开始/提交/回滚块内写入对数据库的更改
不知道如果我理解这个问题。你必须用Commit或Rollback结束一个事务,这样你就知道你做了什么,但是你不想在一个额外的变量中记住这一点?你可以将Tx和bool包装在自己的RememberingTx中,这会减少行数。关于GC问题:无论你是否设置为零,无关紧要:一旦没有引用它,内存将被回收。所以:是的,你可以有'var tx * Tx;剪断;如果cond {tx.Commit; tx = nil} else {tx.Rollback};剪断;如果tx == nil {被提交} else {被回滚}'但它感觉很难看。 – Volker 2013-04-24 12:28:18
这就是它的意义,但是如果Tx不为零,则会有一个延迟函数进行回滚。一旦交易提交,交易无法使用,所以我打算将它设置为零。这不是很好,但是尝试回滚并测试错误消息也不是很好。问题是AFAIK没有办法测试事务是否从Tx“完成”。我不知道为什么这样做,也许是表现。 – 2013-04-24 18:01:25