在现实世界中处理交易

3

我重新提出这个问题,因为它没有得到回应。

我正在尝试找出正确的处理数据库事务的方法。我看到的所有关于如何执行事务的内容都非常基础,大致如下:

  1. 运行 "begin" 命令开始事务
  2. 运行你的查询。
  3. 如果一切正常运行,则提交事务。

我明白了,但是我不知道如何处理错误(死锁)。我听说有两个选择:

  1. 向用户显示错误并说“请再试一次”
  2. 立即重试,直到成功为止。

对我来说,因为技术问题告诉用户再试一次似乎不好——真正的应用程序经常这样做吗?这是我有时看到的“哎呀,出了点问题”的异常错误吗?因为这是一个网站,所以用户甚至不应该知道数据库的存在。

所以我有几个问题:

  1. 在涉及多个用户的数据中,我应该采取哪种失败处理方法?
  2. 如果我选择“立即重试”选项,这对于复杂的PHP脚本意味着什么?从头重新启动整个请求?我担心这会引起更多的问题。
  3. 还有第三个选择吗?
3个回答

1
我使用的解决方案是设置一个重试循环,比如说3次(我认为大多数应用程序在现实生活中不会超过1次重试)。在这个循环中,必须完成所有交易请求,即写请求和读请求。
非常重要的一点是在事务内部执行读请求,因为这会设置锁定并且是以真正的隔离级别获取数据的唯一方式。
然后,所有这些请求都在一个begin/commit块中,带有try/catch。在catch部分中,我运行回滚并重新抛出异常。
通过重新抛出异常,您可以在更高层次上捕获它,这是您可以决定重新运行(3次循环)或将其发送给用户的级别。
根据您的应用程序编码方式,有几种解决方案可以以良好的方式处理此问题:
  • 使用 transactionManager 对象负责 begin/commit/rollack,所有事务中的查询都在事务中进行。
  • 遵循规则,例如“所有事务都由控制器处理,没有 DAO 或 DB 级别的对象知道是否有事务正在运行”。
  • 甚至可以使用仅供 transactionManager 使用的专用数据库连接(具有写权限),并保留原始的只读数据库连接以供其他用途。

0

事务期间的死锁通常表示您正在尝试更新其他人与您同时更新的内容。如何处理取决于用户执行的操作。

在某些情况下,这可能不是问题,您可以重试操作,但我认为在大多数情况下,您应该向用户生成错误,因为您无法知道哪个更新是“正确”的。


0

这份文档中的一些建议我认为并不真实,例如总是以相同的顺序从所有应用程序和维护任务中访问表格...如果您确实有事务需求并真正测试冒险操作,则很可能需要一些非常高的隔离锁(序列化),并且您将遇到死锁和锁超时异常,最好的建议是文档中所说的,为重新运行事务做好准备(而不是用户)。 - regilero

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接