dream752614590
2017-10-07 06:41 阅读 158
已采纳

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(),
    ]);
}
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

3条回答 默认 最新

  • 已采纳
    doujuanju3076 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 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 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.

    点赞 评论 复制链接分享

相关推荐