Singleton类和mysqli事务

时间:2014-08-26 21:48:25

标签: php mysql mysqli transactions

我有一个用于数据库连接的单例类DataBase:

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() {}
}

我在许多其他类中使用这个单例并从构造函数中检索数据库连接,例如:

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.
  }

}

class Product
{
  public $db;

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

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

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

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

此代码如何在多用户环境中工作,其中所有用户从sigleton类共享相同的连接?

2 个答案:

答案 0 :(得分:5)

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

但是,你应该确保你没有使用持久连接(阅读更多关于PHP和mysqli http://php.net/manual/en/mysqli.quickstart.connections.php的连接处理。持久连接在脚本之间汇集并可能暴露你的应用程序交易干扰的风险。

另外,请记住某些语句会导致隐式提交(如http://php.net/manual/en/mysqli.quickstart.transactions.php所述)。 您还应该验证,在脚本执行期间,您与DB的连接没有超时(在某些情况下可能会发生)。我首先检查MySQL的wait_timeout http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#sysvar_wait_timeout设置。

IMO你也应该认真思考你的应用程序的设计。我坚信,DB对象应仅在Model对象中可用,并且只能从它们内部调用,而不是在代码中的任何地方显式调用。

如果您决定考虑事务 - 请记住在DataBase类中添加aproppriate方法(如在对象销毁时添加autocommit(TRUE)和rollback(),如果有事务已启动)。安全比抱歉更好。

我强烈建议您选择(或更改您的数据库引擎)到InnoDB(对表锁定和事务的强大支持) - 在The InnoDB Transaction Model and Locking中阅读更多相关信息。此外,关于交易的大量有用信息也在以下文档中:Mysql transactions and locking

答案 1 :(得分:1)

是的,如果用户从webserver apache,nginx等访问你的phps,你的代码在多用户环境中可以正常工作.php会创建一个新的连接资源(你可以在mysql的proccess列表中看到它们)。你的单例数据库类只保证在单个请求中包含php或类需要连接的所有内容,所有这些都将使用该连接, 如果你没有使用一些pctnl fork流程,逻辑上你的所有代码都将按顺序运行,这将保证你的所有提交和回滚都能正常工作。

当然,如果你想做一些myisam不支持交易的交易查询,你的表应该是innoDB。