Php 单例类和mysqli事务

Php 单例类和mysqli事务,php,mysql,mysqli,transactions,Php,Mysql,Mysqli,Transactions,我有一个用于共享数据库连接的单例类数据库: class DataBase { private static $mysqli; final private function __construct() {} public static function getInstance() { if (!is_object(self::$mysqli)) self::$mysqli = new mysqli($H,$U,$P,$B); return self::$mysq

我有一个用于共享数据库连接的单例类
数据库

class DataBase
{
  private static $mysqli;

  final private function __construct() {}

  public static function getInstance()
  {
    if (!is_object(self::$mysqli)) self::$mysqli = new mysqli($H,$U,$P,$B);
    return self::$mysqli;
  }

  private function __destruct()
  {
    if (self::$mysqli) self::$mysqli->close();
  }

  private function __clone() {} //no cloning in singleton
}
我在许多其他类中使用此singleton对象,并在每个类构造函数中从singleton检索数据库连接,例如:

class Customer
{
  public $db;

  function __construct()
  {
    $this->db=DataBase::getInstance();
  }

  public function create()
  {
    $this->db->query('INSERT INTO customers SET ... WHERE id=100'); //e.g.
  }

}

由于我的所有类实际上都共享singleton类提供的相同连接,所以我的问题是我是否可以从一个类启动数据库事务,然后从另一个类回滚/提交它。我的实际意思是,下面的代码是一个正确创建的db事务,用于在一个数据库事务中创建客户和产品(类建模db记录):

$Customer=new Customer();
$Customer->db->begin_transaction();
...
$Customer->create();
...
$Product=new Product();
$Product->create();
...
$Product->db->commit();

在所有用户共享来自sigleton类的相同连接的多用户环境中,该代码将如何工作?

正如@Marc B所提到的,事务是基于连接的,因此通常您可以在两个不同的对象中启动和提交事务

但是,您应该确保没有使用持久连接(请阅读有关PHP和mysqli处理连接的更多信息。持久连接在脚本之间汇集,可能会使您的应用程序面临事务干扰的风险)

另外,请记住,某些语句会导致隐式提交(如上所述)。 您还应该验证与DB的连接在脚本执行期间没有超时(在某些情况下可能会发生)

在我看来,您还应该认真考虑应用程序的设计。我坚信,DB对象应该只在模型对象中可用,并且只能从模型对象内部调用,而不能在代码中的任何地方显式调用

如果您决定考虑事务,请记住在数据库类中放置适当的方法(如在对象销毁时添加autocommit(TRUE)和rollback(),如果有事务启动)。安全总比抱歉好


我强烈建议您选择(或更改db引擎)InnoDB(非常支持表锁定和事务)-阅读中的更多信息。关于事务的大量有用信息也在这里的文档中:。

是的,如果用户从Web服务器apache、nginx等访问您的php,那么您的代码在多用户环境中可以正常工作。php将创建一个新的连接资源(您可以在mysql的进程列表中看到它们).您的singleton DB类只保证在单个请求中,任何包含php或类的请求都需要连接,所有请求都将使用该连接, 如果您没有使用某些pctnl fork流,那么逻辑上所有代码都将按顺序运行,这将保证所有提交和回滚都能正常工作


当然,如果要执行某些事务查询,您的表应该是innoDB。myisam不支持事务。

事务是每个连接。如果您对象的所有实例都使用相同的连接,那么您肯定可以在一个对象中
启动
,在另一个对象中
回滚
。问题是您是否应该。除非您的对象是基于这样一种理解编写的,即它们的Db连接的基础可以在背后完全改变,否则您将遇到麻烦。假设上面带有开始/提交事务的代码位于一个PHP页面中。我在问自己,如果两个用户同时启动此页面,会发生什么情况。可以吗一个用户在事务中干扰另一个用户。您可能想对该模式进行一些研究。php中的持久DB连接不会使DB会话保持活动状态,但锁定确实会导致问题。现在它的工作方式有点奇怪。感谢@Kleskowy提供您的建议和链接,以供进一步阅读,您的一些建议已经发布od但众所周知且通用的,如使用InnoDB(当然),添加autocommit()(我使用begin_transaction()与autocommit(FALSE)相同),建议仅在模型对象中使用DB相关功能(我的客户和产品当然是模型对象,只有他们使用DB),很好地利用对象销毁方法进行事务回滚(以防万一,因为目前我只在捕获异常时进行回滚)。这是一篇优秀的帖子@Kleskowy。那么你是MVC模式的支持者吗?@b_dubb是的,MVC或GTFO;)没有意大利面代码,对象使构建和调试任何应用程序变得更加简单和干净。因此,在这段代码中,Apache2服务器上的PHP保证了多用户环境中用户之间的隔离。如果我理解正确,PHP将为每个用户(会话)创建一个单例类!?所以连接将只在用户范围内重用,而不是在不同的用户之间重用!是的,对于每个http请求,php将创建一个到db的新连接,但是您的singleton类将为每个请求提供一个连接,只要您在所有包含的类phpes等中使用它。
$Customer=new Customer();
$Customer->db->begin_transaction();
...
$Customer->create();
...
$Product=new Product();
$Product->create();
...
$Product->db->commit();