【问题标题】:Doctrine: How to prevent transaction from becoming 'rollback only' through caught exception?教义:如何通过捕获的异常防止事务成为“仅回滚”?
【发布时间】:2019-06-18 07:12:32
【问题描述】:

由于postRemove 事件处理程序中的异常,删除实体失败。即使捕获到异常,删除也会失败,因为无法再提交事务。 如何解决?

完整的故事:

我需要使用Doctrine 在基于Symfony 3.4 的网络服务中跟踪一些已删除的实体。

为此,我创建了一个EventSubscriber,它处理postRemove 事件以检查是否需要记录已删除的实体。在这种情况下,实体 UUID 存储在数据库的 DeleteLog 表中。

这很好用,但在极少数情况下,DeleteLogEntry 的持久化会失败,因为给定 UUID 的日志条目已经存在,它需要是唯一的。

这个问题的根源是一些我无法改变自己的第 3 方代码。作为一个临时解决方案,试图抓住UniqueConstraintViolationException。这并不能解决问题,因为现在我得到了ConnectionException

事务提交失败,因为事务已被标记为 仅回滚。

有没有可能解决这个困境?

当然,我可以在创建新的之前检查具有给定 UUID 的 DeleteLogEntry 是否存在。但由于此问题仅在极少数情况下发生,因此大多数情况下检查结果是否定的。当然,无论如何运行检查不会对性能造成灾难性影响,但似乎不是最佳解决方案。

是否有可能捕获异常并防止事务被标记为仅回滚?

【问题讨论】:

    标签: symfony exception transactions doctrine


    【解决方案1】:

    不,无法阻止交易被标记。

    Doctine 为postRemove 启动一个nested transaction,如果失败,则不应提交其他事务。在这种情况下,仅将事务标记为回滚(甚至关闭实体管理器)是预期行为,因为 Doctrine 没有其他方法可以确保一致性,因为不支持真正的嵌套事务。

    如果性能不是问题,那么检查DeleteLogEntry 是一个不错的选择。

    其他可能的解决方法:

    • 将 ID 临时存储在某处(Redis、Memcache、文件等),并在提交初始删除后稍后更新DeleteLogEntry
    • 使用单独的实体管理器/连接来更新DeleteLogEntry
    • 移除唯一约束并使用后台任务来监视重复项

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-02
      • 2013-03-27
      • 2016-06-19
      • 1970-01-01
      • 2010-12-14
      • 2020-04-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多