使用Models时如何在PHP Active Record中创建事务?

时间:2014-07-10 14:36:31

标签: php mysql activerecord transactions

我正在使用PHP Active Record开发一个项目并且是新手,我真的开始喜欢它了。所有对象都是ActiveRecord模型的扩展

class User extends Model {

}

class Item extends Model {

}
.
.
.

现在我的代码将有类似的内容(users表包含属于用户的项目的计数,items表包含项目)。

    $user = User::find_by_id($id);
    $user->num_items++;
    $item = new Item();
    //Do stuff with the item
    $user->save();
    $item->save();

现在我担心理论上的机会,当网站遭受重创或者数据库被拆除进行维护时(是的,这些事情与我有关)。由于这些陈述理论上不在交易中:

    $user->save();
    //User table is updated successfully
    //----- MySQL goes Down Here -------/
    $item->save(); //This won't run, now the user's table may say he has 4 items but he only has 3 since the last one didn't get inserted

我希望能够将用户和项目保存在一起,如果一方失败则会回滚。我知道如何在手动MySQL中执行此操作,但这违背了使用ORM的目的。

2 个答案:

答案 0 :(得分:3)

对于仍在使用此库的人来说,它可能会有用。 每个模型都有交易方法

$user = User::find_by_id($id);
$item = new Item();

$entity::transaction(function() use ($user, $item) {
      //Do stuff with the items...
       $user->name = 'somename';
       $user->save();
       $item->quantity = 0;
       $item->save();
   });

它位于\ ActiveRecord \ Model命名空间(它是项目模型的父类)

您可以使用此公共静态方法使用闭包运行事务查询。 例如:

\ActiveRecord\Config::initialize(function ($cfg) use ($hostname, $username, $password, $database, $port) {
            $cfg->set_model_directory('/src/Entity');
            $cfg->set_connections(
                array(
                    'development' => 'mysql://' . $username . ':' . $password . '@' . $hostname . '/' . $database
                )
            );
        });

以上事务静态方法使用模型中的连接实例,如果每个模型具有相同的连接,则不会有任何问题。例如,我的所有模型只有一个连接

  YourModel::transaction(function()
      {
        YourModel::create(array("name" => "blah"));
        throw new Exception("rollback!");
      });

      YourModel::transaction(function()
      {
        YourModel::create(array("name" => "blah"));
        return false; # rollback!
      });

如果你有一些内部验证等,你可以抛出\ Exception或从你的闭包中返回false并且事务将被回滚

  $user = User::find_by_id($id);
   $item = new Item();
   $connection = ConnectionManager::get_connection();
   $connection->transaction();
   try{
       //Do stuff with the items...
       $user->name = 'somename';
       $user->save();
       $item->quantity = 0;
       $item->save();
       $connection->commit();
   }
   catch (\Exception $exception){
       throw $exception;
       $connection->rollback();
   }

您也可以像往常一样获取连接实例并开始交易

{{1}}

ps:这里还有一些例子http://www.phpactiverecord.org/docs/ActiveRecord/Model#methodtransaction

答案 1 :(得分:0)

在save()函数实现mysql_query的情况下,这种代码应该可以解决问题。 由您自己将其封装在一个漂亮的界面中,以便那些丑陋的mysql_querys也由您的活动记录框架处理

    mysql_query("SET AUTOCOMMIT=0");
    mysql_query("START TRANSACTION");

    $a1=$user->save();
    $a2=$item->save();

    if ($a1 and $a2) {
        mysql_query("COMMIT");
    } else {        
        mysql_query("ROLLBACK");
    }