dream752614590
2017-10-07 06:41
浏览 463
已采纳

Laravel事务回滚似乎不起作用

I am running laravel 5.4 and noticed that rollbacks in transactions do not work. I set my database engine to InnoDB in the settings.php file and tried DB::rollback(); and DB::rollBack(); (i.e. upper and lower case b) but it does not roll back my database.

I wrote a unit test bellow. It creates a record, commits it, then rolls back. However, the last assertion fails. After it rolls back, the record is still found in the database. Is there something I am missing? Or is there a bug with laravel?

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(),
    ]);
}

图片转代码服务由CSDN问答提供 功能建议

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

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

  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-> assertDatabaseMissing('seasons',[
'start_date'=> Carbon :: now(),'end_date'=> Carbon :: now()  ,
]); 
} 
   
 
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • doujuanju3076 2017-10-07 06:47
    已采纳

    The transaction consists of three steps:

    You start it with DB::beginTransaction or MySQL equivalent BEGIN TRANSACTION, then you execute the commands you need to and then (and here's the important part) you either COMMIT or ROLLBACK

    However once you've committed the transaction is done, you cant roll it back anymore.

    Change the test to:

    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(),
        ]);
    }
    

    This should work because until the transaction is rolled back the database "thinks" the record is in there.

    In practice when using transactions you want to use what's suggested in the docs, for example:

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

    This will ensure atomicity of wrapped operations and will rollback if an exception is thrown within the function body (which you can also throw yourself as a means to abort if you need to).

    已采纳该答案
    打赏 评论
  • dpw5865 2017-10-07 06:48

    You cannot rollback once you commit.As i can see you have used commit

    DB::commit(); 
    

    before rollback

    so you can rollback only when it will fails to commit .you can use try catch block

    DB::beginTransaction();
        try {
            DB::insert(...);
           DB::commit();
        } catch (\Exception $e) {
            DB::rollback();
    
        }
    
    打赏 评论
  • doww38701 2017-10-07 07:02

    Emmm... you have misunderstood how transactions work.

    After having begun a transaction, you could either commit it or rollback it. Committing means that all changes you did to the database during the transaction so far are "finalized" (i.e. made permanent) in the database. As soon as you have committed, there is nothing to roll back.

    If you want to roll back, you have to do so before you commit. Rolling back will bring the database into the state it was before you have started the transaction.

    This means you exactly have two options:

    1) Begin a transaction, then commit all changes made so far.

    2) Begin a transaction, then roll back all changes made so far.

    Both committing and rolling back are final actions for a transaction, i.e. end the transaction. When having committed or rolled back, the transaction is finished from the database's point of view.

    You could also look at this in the following way:

    By starting a transaction, you are telling the database that all following changes are preliminary / temporary. After having done your changes, you can either tell the database to make those changes permanent (by committing), or you tell the database to throw away (revert) the changes (by rolling back).

    After you have rolled back, the changes are lost and thus cannot be committed again. After you have committed, the changes are permanent and thus cannot be rolled back. Committing and rolling back is only possible as long as the changes are in the temporary state.

    打赏 评论

相关推荐 更多相似问题