我可以将整个HTTP请求包装在一个事务中吗?

时间:2015-07-03 18:14:51

标签: php mysql pdo transactions

我有一个PHP应用程序,其中自定义模型层构建在PDO之上。我的每个模型都是一个单独的类(具有公共基类),它管理与给定表的交互(给定表的所有SELECT,INSERT和UPDATE都是给定类的实例方法)。但是,所有类共享一个PDO对象,使用单个数据库连接,以非常简单的依赖注入形式传递给模型类的构造函数。

这有点简化,但它的工作原理如下:

<?php
    $pdo = new \PDO(/*connection details*/);
    $modelA = new ModelA($pdo);
    $modelB = new ModelB($pdo);
    $thingA = $modelA->find(1234); //where 1234 is the primary key
    $thingB = $modelB->create([
        'modelb_id' => $thingA->id,
        'notes' => 'This call generates an runs an insert statement based on the array of fields and values passed in, applying specialized business logic, and other fun stuff.'
    ]);
    print_r($thingB); // Create returns an object containing the data from the newly created row, so this would dump it to the screen.

无论如何,目前,所有内容都只是通过PDO准备好的语句运行并立即提交,因为我们没有使用交易。在大多数情况下,这很好,但我们遇到了一些问题。

首先,如果数据库交互比上面看到的更复杂,那么您可以生成一个请求,该请求生成大量SQL查询,包括几个相互关联的INSERT和UPDATE。如果在执行过程中遇到错误或异常,则数据库内容的前半部分已提交到数据库,但之后的所有内容都不会运行。所以你得到孤立的记录和其他不良数据。我知道这基本上是交易被发明解决的确切问题,因此使用它们似乎是一个令人信服的案例。

我们遇到的另一件事是在高流量运行时间歇性的MySQL死锁。我仍然试图深入了解这些内容,但我怀疑交易在这方面也会有所帮助。

这是事情的结果。我的数据库逻辑是抽象的(应该是这样),最终散布了一点。我想要做的就是在创建PDO对象时创建一个事务,然后用PDO对象运行的所有查询都将成为该事务的一部分。然后,作为我的应用程序的HTTP请求的拆除序列的一部分,在完成所有操作后提交事务。在我的错误处理逻辑中,我可能想要回滚。

在我尝试完全实现这一目标之前,我会做一些实验,但我希望得到一些可能已经走上正轨的人的一些反馈,关于我是否走在正确的轨道上,或者这实际上是一个糟糕的想法,或一些更成功实施的技巧。我也有一些具体的问题:

将事务中的所有内容包装都会导致性能下降吗?看起来如果您有多个同时进行的事务,它们必须排队,因此第一个事务可以在第二个事务可以运行之前完成。否则,您必须缓存数据库的状态,以便一个事务中的所有事件都可以遵循其逻辑进展?也许不吧。也许它实际上更快。我不知道。

我们使用MySQL复制。一个环境使用MySQL的Master-Slave支持,bin日志格式设置为STATEMENT。另一个环境使用Percona Cluster,具有Master-Master复制。这个模型有复制含义吗?

交易是否超时?当它超时时,它是提交还是回滚?我希望我的正常应用程序逻辑将提交或回滚,具体取决于是否存在错误。但如果整个事情崩溃了,那我正在建立的交易会发生什么?

我提到我们正在遇到MySQL死锁。我已经为我的模型添加了一些逻辑,当PDO抛出PDOException时,如果它是1213,我抓住它,睡眠最多3秒,然后再试一次。如果出现死锁或任何PDOException,我的交易会发生什么?它会自动回滚吗?或者它不管它,所以我可以尝试恢复?

我还有哪些其他风险完全忽视了我需要考虑的因素?我可以尝试一下我的想法并做一些测试,但是我担心我所知道的所有东西都能找到工作的情况,但是我不知道要找到的东西会出现什么把它推到野外?

现在,我没有使用连接池,我只为每个请求创建一个连接,在所有模型类之间共享。但是,如果我想稍后进行连接池,那么它如何与事务交互?

我清楚地了解了在创建共享PDO对象时如何以及在何处启动事务。但是提交部分是否有最佳实践?我有一个脚本,可以为每个请求执行其他拆解操作。我可以把它放在那里。我可以将PDO子类化,并将其添加到析构函数中,但我从未在PHP中使用构造函数。

哦,是的,我需要弄清楚嵌套交易的工作原理。在我的初步测试中,看起来你可以多次调用BEGIN,并且第一次调用COMMIT时,它会将所有内容提交回第一个BEGIN。任何后续的COMMIT都不会做太多。这是对的,还是我误解了我的测试?

0 个答案:

没有答案