简体   繁体   English

Laravel事务回滚似乎不起作用

[英]Laravel transaction rollback does not seem to work

I am running laravel 5.4 and noticed that rollbacks in transactions do not work. 我正在运行laravel 5.4并注意到事务中的回滚不起作用。 I set my database engine to InnoDB in the settings.php file and tried DB::rollback(); 我在settings.php文件中将数据库引擎settings.phpInnoDB ,并尝试使用DB::rollback(); and DB::rollBack(); DB::rollBack(); (ie upper and lower case b) but it does not roll back my database. (即大写和小写b),但它不会回滚我的数据库。

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

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 因此,只有在提交失败时才可以回滚。可以使用try catch块

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

    }

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 你启动它DB::beginTransaction或MySQL相当于BEGIN TRANSACTION ,然后你执行你需要的命令,然后(在这里是最重要的部分),你要么 COMMIT 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: 实际上,在使用事务时,您想使用docs中的建议,例如:

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). 这将确保包装操作的原子性,并且如果在函数体内引发异常(如果需要,您也可以抛出异常作为中止的手段),将回滚。

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" (ie 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. 1)开始一个事务,然后提交到目前为止所做的所有更改。

2) Begin a transaction, then roll back all changes made so far. 2)开始一个事务,然后回滚到目前为止所做的所有更改。

Both committing and rolling back are final actions for a transaction, ie 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. 仅当更改处于临时状态时,才可以提交和回滚。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM