You are here

65 事务

admin 的头像
Submitted by admin on 星期四, 2015-06-11 09:28

作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com

    Drupal还支持事务,对于那些不支持事务的数据库,Drupal还包含了一个透明的回退。然而,当你在同一时间,尝试并启动两个事务时,事务就会变得复杂起来。数据库不同,此时的行为也不相同。

    在C/C++里面的嵌套锁中,也存在类似的问题。如果代码已经获得锁A,并尝试去获取锁A时,代码就会进入死循环。你可以在代码中添加检查语句,如果已经获得了锁,那么就不再尝试获取它了,这样就可以避免死循环;但是你也可以提前释放锁。

    在SQL中,我们也存在同样的问题。如果你的代码已经处于一个事务中了,那么启动一个新的事务,这会给你带来非常惊讶和不幸的后果。

    Java通过支持类似于我们下面测试所用的嵌套结构,成功解决了它的锁嵌套问题。Java允许你把函数标记为“同步”("synchronized"),函数在运行前,首先等待锁的释放;当它获得了锁以后,就会执行;当它不再需要时,就会把锁释放。如果在同一个类中,一个同步函数调用另一个,Java将会追踪锁的嵌套。外部的函数获取锁,内部函数执行无锁操作;当外部函数返回时,释放锁。

    尽管我们不能在PHP中把函数声明为“事务的”,但是通过使用带有构造函数和析构函数的对象,我们就可以模拟Java的嵌套逻辑。在一个函数中,在它的第一个操作或者接近于第一个操作的地方,简单的调用"$txn = db_transaction();",就使得函数具有事务特性了。如果一个事务函数调用了另一个,我们的事务抽象层通过在内部嵌套层执行非事务操作(至少在数据库看来是这样),来实现嵌套。

    为了启动一个新事务,在你的代码中简单的调用$txn = db_transaction();即可。只要变量$txn仍然在范围内,那么事务就会保持打开的状态。当$txn被销毁时,事务将被提交。如果你的事务嵌套在另一个里面,那么Drupal会追踪每一个事务,只有当最后一个事务对象超出范围,也就是所有相关的查询都成功执行完毕时,Drupal才会提交最外面的事务。

例如:

<?php
function my_transaction_function() {

  //在这里打开事务
  $txn db_transaction();

  $id db_insert('example')
    ->fields(array(
      'field1' => 'mystring',
      'field2' => 5,
    ))
    ->execute();

  my_other_function($id);

  return $id;

  //在这里,$txn超出了范围,整个事务被提交。
}

function my_other_function($id) {
   //此处,事务仍然是开着的。

  if ($id == 0) {
    db_update('example')
      ->condition('id'$id)
      ->fields(array('field2' => 10))
      ->execute();
  }
}
?>


Drupal版本: