首页 > yii2教程 > yii2数据库使用

yii2 事务操作

执行事务

当顺序地执行多个相关的语句时, 你或许需要将它们包在一个事务中来保证数据库的完整性和一致性。 如果这些语句中的任何一个失败了, 数据库将回滚到这些语句执行前的状态。

 

下面的代码展示了一个使用事务的典型方法:

 

Yii::$app->db->transaction(function($db) {

    $db->createCommand($sql1)->execute();

    $db->createCommand($sql2)->execute();

    // ... executing other SQL statements ...

});

上述代码等价于下面的代码, 但是下面的代码给予了你对于错误处理代码的更多掌控:

 

$db = Yii::$app->db;

$transaction = $db->beginTransaction();

 

try {

    $db->createCommand($sql1)->execute();

    $db->createCommand($sql2)->execute();

    // ... executing other SQL statements ...

    

    $transaction->commit();

    

} catch(\Exception $e) {

 

    $transaction->rollBack();

    

    throw $e;

}

通过调用 beginTransaction() 方法, 一个新事务开始了。 事务被表示为一个存储在 $transaction 变量中的 yii\db\Transaction 对象。 然后,被执行的语句都被包含在一个 try...catch... 块中。 如果所有的语句都被成功地执行了, commit() 将被调用来提交这个事务。 否则, 如果异常被触发并被捕获, rollBack() 方法将被调用, 来回滚事务中失败语句之前所有语句所造成的改变。 throw $e 将重新抛出该异常, 就好像我们没有捕获它一样, 因此正常的错误处理程序将处理它。

 

指定隔离级别

Yii 也支持为你的事务设置隔离级别。 默认情况下, 当我们开启一个新事务, 它将使用你的数据库所设定的隔离级别。 你也可以向下面这样重载默认的隔离级别,

 

$isolationLevel = \yii\db\Transaction::REPEATABLE_READ;

 

Yii::$app->db->transaction(function ($db) {

    ....

}, $isolationLevel);

 

// or alternatively

 

$transaction = Yii::$app->db->beginTransaction($isolationLevel);

Yii 为四个最常用的隔离级别提供了常量:

 

yii\db\Transaction::READ_UNCOMMITTED - 最弱的隔离级别,脏读、不可重复读以及幻读都可能发生。

yii\db\Transaction::READ_COMMITTED - 避免了脏读。

yii\db\Transaction::REPEATABLE_READ - 避免了脏读和不可重复读。

yii\db\Transaction::SERIALIZABLE - 最强的隔离级别, 避免了上述所有的问题。

除了使用上述的常量来指定隔离级别, 你还可以使用你的数据库所支持的具有有效语法的字符串。 比如,在 PostgreSQL 中, 你可以使用 SERIALIZABLE READ ONLY DEFERRABLE。

 

请注意,一些数据库只允许为整个连接设置隔离级别, 即使你之后什么也没指定, 后来的事务都将获得与之前相同的隔离级别。 使用此功能时,你需要为所有的事务明确地设置隔离级别来避免冲突的设置。 在本文写作之时, 只有 MSSQL 和 SQLite 受这些限制的影响。

 

注意: SQLite 只支持两种隔离级别, 所以你只能使用 READ UNCOMMITTED 和 SERIALIZABLE。 使用其他级别将导致异常的抛出。

注意: PostgreSQL 不支持在事务开启前设定隔离级别, 因此,你不能在开启事务时直接指定隔离级别。 你必须在事务开始后再调用 yii\db\Transaction::setIsolationLevel()。

嵌套事务

如果你的数据库支持保存点, 你可以像下面这样嵌套多个事务:

 

Yii::$app->db->transaction(function ($db) {

    // outer transaction

    

    $db->transaction(function ($db) {

        // inner transaction

    });

});

或者,

 

$db = Yii::$app->db;

$outerTransaction = $db->beginTransaction();

try {

    $db->createCommand($sql1)->execute();

 

    $innerTransaction = $db->beginTransaction();

    try {

        $db->createCommand($sql2)->execute();

        $innerTransaction->commit();

    } catch (\Exception $e) {

        $innerTransaction->rollBack();

        throw $e;

    }

 

    $outerTransaction->commit();

} catch (\Exception $e) {

    $outerTransaction->rollBack();

    throw $e;

}

 

美景欣赏

美景欣赏

关闭
感谢您的支持,我会继续努力!
扫码打赏,建议金额1-10元


提醒:打赏金额将直接进入对方账号,无法退款,请您谨慎操作。