【问题标题】:Laravel transaction rollback does not seem to workLaravel 事务回滚似乎不起作用
【发布时间】:2017-10-07 06:41:07
【问题描述】:

我正在运行laravel 5.4 并注意到事务中的回滚不起作用。我在settings.php 文件中将我的数据库引擎设置为InnoDB,并尝试了DB::rollback();DB::rollBack();(即大写和小写b),但它没有回滚我的数据库。

我在下面写了一个单元测试。它创建一个记录,提交它,然后回滚。但是,最后一个断言失败。回滚后,该记录仍可在数据库中找到。有什么我想念的吗?还是laravel有bug?

public function testRollback()
{
    $this->artisan('migrate:refresh', [
        '--seed' => '1'
    ]);

    DB::beginTransaction();

    Season::create(['start_date' => Carbon::now(), 'end_date' => Carbon::now(),]);
    DB::commit();
    $this->assertDatabaseHas('seasons', [
        'start_date' => Carbon::now(), 'end_date' => Carbon::now(),
    ]);

    DB::rollBack();
    // This assertion fails. It still finds the record after calling roll back
    $this->assertDatabaseMissing('seasons', [
        'start_date' => Carbon::now(), 'end_date' => Carbon::now(),
    ]);
}

【问题讨论】:

    标签: php mysql laravel transactions


    【解决方案1】:

    交易包括三个步骤:

    您以DB::beginTransaction 或MySQL 等效的BEGIN TRANSACTION 开始它,然后执行所需的命令,然后(这是重要的部分)或者 COMMIT 或者 ROLLBACK

    但是一旦你提交了事务,你就不能再回滚了。

    将测试改为:

    public function testRollback()
    {
        $this->artisan('migrate:refresh', [
            '--seed' => '1'
        ]);
    
        DB::beginTransaction();
    
        Season::create(['start_date' => Carbon::now(), 'end_date' => Carbon::now(),]);
    
        $this->assertDatabaseHas('seasons', [
            'start_date' => Carbon::now(), 'end_date' => Carbon::now(),
        ]);
    
        DB::rollback();
    
        $this->assertDatabaseMissing('seasons', [
            'start_date' => Carbon::now(), 'end_date' => Carbon::now(),
        ]);
    }
    

    这应该有效,因为在事务回滚之前,数据库“认为”记录在那里。

    在实际使用交易时,您希望使用the docs 中建议的内容,例如:

    DB::transaction(function()
    {
        DB::table('users')->update(array('votes' => 1));
    
        DB::table('posts')->delete();
    });
    

    这将确保包装操作的原子性,并且如果在函数体内引发异常,将回滚(如果需要,您也可以将自己作为中止的一种方式)。

    【讨论】:

      【解决方案2】:

      一旦提交就不能回滚。我可以看到你已经使用了提交

      DB::commit(); 
      

      回滚前

      所以只有在提交失败时才能回滚。你可以使用 try catch 块

      DB::beginTransaction();
          try {
              DB::insert(...);
             DB::commit();
          } catch (\Exception $e) {
              DB::rollback();
      
          }
      

      【讨论】:

        【解决方案3】:

        Emmm...您误解了交易的运作方式。

        开始事务后,您可以提交或回滚。提交意味着到目前为止您在事务期间对数据库所做的所有更改都在数据库中“最终确定”(即永久化)。一旦你提交了,就没有什么可以回滚的了。

        如果您想回滚,您必须在提交之前这样做。回滚将使数据库恢复到您开始事务之前的状态。

        这意味着你有两个选择:

        1) 开始一个事务,然后提交到目前为止所做的所有更改。

        2) 开始一个事务,然后回滚到目前为止所做的所有更改。

        提交和回滚都是事务的最终操作,即结束事务。提交或回滚后,从数据库的角度来看,事务已完成。

        你也可以这样看:

        通过启动事务,您是在告诉数据库所有后续更改都是初步的/临时的。完成更改后,您可以告诉数据库使这些更改永久化(通过提交),或者告诉数据库丢弃(恢复)更改(通过回滚)。

        回滚后,更改将丢失,因此无法再次提交。提交后,更改是永久性的,因此无法回滚。只要更改处于临时状态,就可以提交和回滚。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-10-04
          • 2021-09-27
          • 1970-01-01
          • 2011-01-17
          • 1970-01-01
          • 2019-03-28
          • 2021-07-19
          相关资源
          最近更新 更多