运行 在 PHP 中插入函数作为事务
Run insert functions in PHP as transaction
我有一个模型 class,它位于 Model.php,我有两个模型,如 ModelOne 和 ModelTwo,分别位于 ModelOne.php 和 ModelTwo.php。这些模型扩展了基础模型 class。模型 class 扩展了一个 DatabaseConnector class,它使用 PDO 与数据库交互。
class ModelOne extends Model {
public function storeX($params1) {
$query = 'insert ...';
return $this->insert($query, $params1);
}
}
class ModelTwo extends Model {
public function storeY($params2) {
$query = 'insert ...';
return $this->insert($query, $params2);
}
}
class Model extends DatabaseConnector {/* not related to this question */}
class DatabaseConnector {
private $_mysql;
public function __construct() {
$this->_mysql = new PDO(...);
}
public function insert($query, $params = array()) {
$sql_stmt = $this->_mysql->prepare($query);
foreach($params as $i => $param) {
$sql_stmt->bindValue(++$i, $param['value'], $param['type']);
}
$sql_stmt->execute();
return $this->_mysql->lastInsertId();
}
}
我运行在我的模型中使用两个不同的函数class是这样的:
/* begin transaction */
$model1 = new ModelOne();
$anotherParam = $model1->storeX($params1);
$model2 = new ModelTwo();
$model2->storeY($params2, $anotherParam);
/* end transaction */
我想将这两个存储函数(PDO 中的每个 运行、"prepare"、"bindValue" 和 "execute")作为事务处理到 运行。我应该怎么办?我不想更改我的 MVC 结构。
编辑:
$anotherParam
添加了变量。
不改变您当前的 DatabaseConnector
和 class 继承
如果 storeX()
和 storeY()
方法 return Exception
,您可以使用几个 try...catch
块安排 "transactional" 回退失败对象:
try {
$model1 = new ModelOne();
$anotherParam = $model1->storeX($params1);
} catch (Exception ex) {
//First INSERT failed
//Handle the issue and don't continue
exit;
}
try {
$model2 = new ModelTwo();
$model2->storeY($params2, $anotherParam);
} catch (Exception ex) {
//Second INSERT failed
//Roll back the first INSERT!
$model1->removeX($anotherParam);
}
修改 DatabaseConnector
的使用方式
使用适当的 MySQL 数据库端事务会好得多,但这需要您有一个 单个数据库连接 在各个数据库之间共享ModelX
个对象。
您应该扩展 DatabaseConnector
以很好地处理交易(如@jayxhj 所建议),这将满足您的需求。
如果您 want/need 您的所有模型都使用 DatabaseConnector
class 的相同实例(这将允许您使用来自 你的 ModelX
class 如果你愿意的话),你可以让你的 DatabaseConnector
实现 the singleton pattern。
我不认为你的 ModelX
classes 应该扩展 DatabaseConnector
class - 它们似乎不是更具体的数据库版本连接器。相反,我认为 ModelX
classes 应该像这个例子一样使用 DatabaseConnector
:
在事务中封装调用
//Start transaction
$db = DatabaseConnector::getInstance();
$db->beginTransaction();
try
{
//Do database work
$model1 = new ModelOne();
$anotherParam = $model1->storeX($params1);
$model2 = new ModelTwo();
$model2->storeY($params2, $anotherParam);
//Commit the whole transaction
$db->commit();
}
catch (Exception ex)
{
//Roll back the whole transaction
$db->rollback();
}
型号class
class Model {
private $_mysql;
public function __construct() {
//Get "singleton" instance of the DatabaseConnector (shared between all Models)
$this->_mysql = DatabaseConnector::getInstance();
}
}
数据库连接器class
class DatabaseConnector extends Singleton {
private $_mysql;
public function __construct() {
$this->_mysql = new PDO(...);
}
public function beginTransaction() {
return $this->_mysql->beginTransaction();
}
public function commit() {
return $this->_mysql->commit();
}
public function rollback() {
return $this->_mysql->rollback();
}
}
单例class
class Singleton
{
/**
* @var Singleton The reference to *Singleton* instance of this class
*/
private static $instance;
/**
* Returns the *Singleton* instance of this class.
*
* @return Singleton The *Singleton* instance.
*/
public static function getInstance()
{
if (null === static::$instance) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Protected constructor to prevent creating a new instance of the
* *Singleton* via the `new` operator from outside of this class.
*/
protected function __construct()
{
}
/**
* Private clone method to prevent cloning of the instance of the
* *Singleton* instance.
*
* @return void
*/
private function __clone()
{
}
/**
* Private unserialize method to prevent unserializing of the *Singleton*
* instance.
*
* @return void
*/
private function __wakeup()
{
}
}
@Nerdwood的回答满足你的需求
还有一个办法
try {
$pdo = new PDO(...);
$pdo->beginTransaction();
$model1 = new ModelOne();
$anotherParam = $model1->storeX($params1);
$model2 = new ModelTwo();
$model2->storeY($params2, $anotherParam);
$pdo->commit();
}
catch (Exception $e) {
$pdo->rollback();
}
但您应该修改 DatabaseConnector class 以提供 public 数据库处理程序来支持事务。
Nerdwood 的回答是让它成为语言级别的事务,我的回答是数据库处理事务本身的一种方式。
此外,您应该检查您的数据库引擎是否支持事务。
我有一个模型 class,它位于 Model.php,我有两个模型,如 ModelOne 和 ModelTwo,分别位于 ModelOne.php 和 ModelTwo.php。这些模型扩展了基础模型 class。模型 class 扩展了一个 DatabaseConnector class,它使用 PDO 与数据库交互。
class ModelOne extends Model {
public function storeX($params1) {
$query = 'insert ...';
return $this->insert($query, $params1);
}
}
class ModelTwo extends Model {
public function storeY($params2) {
$query = 'insert ...';
return $this->insert($query, $params2);
}
}
class Model extends DatabaseConnector {/* not related to this question */}
class DatabaseConnector {
private $_mysql;
public function __construct() {
$this->_mysql = new PDO(...);
}
public function insert($query, $params = array()) {
$sql_stmt = $this->_mysql->prepare($query);
foreach($params as $i => $param) {
$sql_stmt->bindValue(++$i, $param['value'], $param['type']);
}
$sql_stmt->execute();
return $this->_mysql->lastInsertId();
}
}
我运行在我的模型中使用两个不同的函数class是这样的:
/* begin transaction */
$model1 = new ModelOne();
$anotherParam = $model1->storeX($params1);
$model2 = new ModelTwo();
$model2->storeY($params2, $anotherParam);
/* end transaction */
我想将这两个存储函数(PDO 中的每个 运行、"prepare"、"bindValue" 和 "execute")作为事务处理到 运行。我应该怎么办?我不想更改我的 MVC 结构。
编辑:
$anotherParam
添加了变量。
不改变您当前的 DatabaseConnector
和 class 继承
如果 storeX()
和 storeY()
方法 return Exception
,您可以使用几个 try...catch
块安排 "transactional" 回退失败对象:
try {
$model1 = new ModelOne();
$anotherParam = $model1->storeX($params1);
} catch (Exception ex) {
//First INSERT failed
//Handle the issue and don't continue
exit;
}
try {
$model2 = new ModelTwo();
$model2->storeY($params2, $anotherParam);
} catch (Exception ex) {
//Second INSERT failed
//Roll back the first INSERT!
$model1->removeX($anotherParam);
}
修改 DatabaseConnector
的使用方式
使用适当的 MySQL 数据库端事务会好得多,但这需要您有一个 单个数据库连接 在各个数据库之间共享ModelX
个对象。
您应该扩展 DatabaseConnector
以很好地处理交易(如@jayxhj 所建议),这将满足您的需求。
如果您 want/need 您的所有模型都使用 DatabaseConnector
class 的相同实例(这将允许您使用来自 你的 ModelX
class 如果你愿意的话),你可以让你的 DatabaseConnector
实现 the singleton pattern。
我不认为你的 ModelX
classes 应该扩展 DatabaseConnector
class - 它们似乎不是更具体的数据库版本连接器。相反,我认为 ModelX
classes 应该像这个例子一样使用 DatabaseConnector
:
在事务中封装调用
//Start transaction
$db = DatabaseConnector::getInstance();
$db->beginTransaction();
try
{
//Do database work
$model1 = new ModelOne();
$anotherParam = $model1->storeX($params1);
$model2 = new ModelTwo();
$model2->storeY($params2, $anotherParam);
//Commit the whole transaction
$db->commit();
}
catch (Exception ex)
{
//Roll back the whole transaction
$db->rollback();
}
型号class
class Model {
private $_mysql;
public function __construct() {
//Get "singleton" instance of the DatabaseConnector (shared between all Models)
$this->_mysql = DatabaseConnector::getInstance();
}
}
数据库连接器class
class DatabaseConnector extends Singleton {
private $_mysql;
public function __construct() {
$this->_mysql = new PDO(...);
}
public function beginTransaction() {
return $this->_mysql->beginTransaction();
}
public function commit() {
return $this->_mysql->commit();
}
public function rollback() {
return $this->_mysql->rollback();
}
}
单例class
class Singleton
{
/**
* @var Singleton The reference to *Singleton* instance of this class
*/
private static $instance;
/**
* Returns the *Singleton* instance of this class.
*
* @return Singleton The *Singleton* instance.
*/
public static function getInstance()
{
if (null === static::$instance) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Protected constructor to prevent creating a new instance of the
* *Singleton* via the `new` operator from outside of this class.
*/
protected function __construct()
{
}
/**
* Private clone method to prevent cloning of the instance of the
* *Singleton* instance.
*
* @return void
*/
private function __clone()
{
}
/**
* Private unserialize method to prevent unserializing of the *Singleton*
* instance.
*
* @return void
*/
private function __wakeup()
{
}
}
@Nerdwood的回答满足你的需求
还有一个办法
try {
$pdo = new PDO(...);
$pdo->beginTransaction();
$model1 = new ModelOne();
$anotherParam = $model1->storeX($params1);
$model2 = new ModelTwo();
$model2->storeY($params2, $anotherParam);
$pdo->commit();
}
catch (Exception $e) {
$pdo->rollback();
}
但您应该修改 DatabaseConnector class 以提供 public 数据库处理程序来支持事务。
Nerdwood 的回答是让它成为语言级别的事务,我的回答是数据库处理事务本身的一种方式。
此外,您应该检查您的数据库引擎是否支持事务。