0

我了解事务如何工作以及一切按预期运行,但我不喜欢访问连接以提交或回滚事务的方式。

我有 3 个服务类可以访问同一个单例连接对象。我想将这三件事包装在一个事务中,所以我这样做:

try {
  $service1 = new ServiceOne;
  $service2 = new ServiceTwo;
  $service3 = new ServiceThree;

  $service1->insertRec1($data);
  $service2->deleteRec2($data);
  $service3->updateRec3($data);

  $service1->getSingletonConnection()->commit();
}
catch(Exception $ex) {
  $service1->getSingletonConnection()->rollback();
}

getSingletonConnection 返回的连接对象只是 oci8 连接的包装器,提交是oci_commit; 回滚是oci_rollback

正如我所说,这是因为它们都在访问同一个连接,但是通过任意服务对象访问连接感觉不对。此外,我的应用程序中使用了两个不同的数据库,因此我需要确保检索并提交正确的数据库……但不确定是否有任何解决方法。

有没有更好的方法来处理交易?

4

2 回答 2

2

通过任意服务对象访问连接感觉不对。

我100%同意你。

在我看来,如果每个服务只构成数据库事务的一部分,那么服务就不能直接负责确定要使用的数据库会话。您应该在定义事务的代码级别选择和管理连接。

因此,您当前的代码将被修改为:

try {
  $conn = getSingletonConnection();
  $service1 = new ServiceOne($conn);
  $service2 = new ServiceTwo($conn);
  $service3 = new ServiceThree($conn);

  $service1->insertRec1($data);
  $service2->deleteRec2($data);
  $service3->updateRec3($data);

  $conn->commit();
}
catch(Exception $ex) {
  $conn->rollback();
}

看起来这会简化您的两个数据库问题的处理,因为只有一个地方可以决定使用哪个连接,并且您将直接引用该连接,直到您结束事务。

如果您想从单例连接扩展到连接池,这是我能想到的唯一保证所有三个服务调用使用相同连接的方法。

于 2011-03-08T14:57:38.570 回答
1

单一连接本质上没有任何问题。如果您有多个连接,则每个连接都运行一个独立的事务。你基本上有两个选择。

  • 为三个服务中的每一个维护当前的单个连接对象
  • 为每个服务维护单独的连接(具有相关的开销),并分别提交/回滚每个单独的连接(不是特别安全,因为你不能保证 ACID 的一致性)

作为一种绕过您要连接的两个独立数据库实例的方法:使用 db 链接,以便您只连接到单个数据库

于 2011-03-07T15:15:14.813 回答