我有一个单例类 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() {} //no cloning in 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.
}
}
和
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.
}
}
因为我所有的类实际上共享单例类给定的相同连接,我的问题是我可以从一个类开始数据库事务并从另一个类回滚/提交它。实际上我的意思是,下面的代码是一个正确创建的数据库事务,用于在一个数据库事务中创建客户和产品(在后面建模数据库记录的类):
$Customer=new Customer();
$Customer->db->begin_transaction();
...
$Customer->create();
...
$Product=new Product();
$Product->create();
...
$Product->db->commit();
这段代码如何在多用户环境中工作,在多用户环境中,所有用户都共享来自 sigleton 类的相同连接?
最佳答案
正如@Marc B 提到的,事务是基于连接的,因此通常您能够在两个不同的对象中启动和提交事务。
但是,您应该确保您没有使用持久连接(阅读更多关于 PHP 和 mysqli 处理连接的信息 http://php.net/manual/en/mysqli.quickstart.connections.php 。持久连接在脚本之间汇集并可能使您的应用面临风险交易干扰。
此外,请记住某些语句会导致隐式提交(如 http://php.net/manual/en/mysqli.quickstart.transactions.php 所述)。 您还应该验证,您与数据库的连接在脚本执行期间不会超时(在某些情况下可能会发生)。我将从检查 MySQL 的 wait_timeout http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#sysvar_wait_timeout 开始设置。
IMO,您还应该认真考虑应用程序的设计。我坚信,DB 对象应该只在 Model 对象中可用,并且只能从它们内部调用,而不是在代码中的任何地方显式调用。
如果您决定考虑事务 - 请记住在您的数据库类中放置适当的方法(如在对象销毁时添加自动提交 (TRUE) 和回滚 (),如果事务已启动)。安全总比后悔好。
我强烈建议您选择(或更改您的数据库引擎)InnoDB(对表锁定和事务的强大支持)- 在 The InnoDB Transaction Model and Locking 中阅读更多相关信息.此处的文档中还有大量有关交易的有用信息:Mysql transactions and locking .
关于php - 单例类和mysqli事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25515710/