Laravel DB::rollback() 不适用于事务处理

Posted

技术标签:

【中文标题】Laravel DB::rollback() 不适用于事务处理【英文标题】:Laravel DB::rollback() doesn't work for transaction processes 【发布时间】:2018-05-11 12:03:45 【问题描述】:

首先我的引擎是 innoDB,我已经在 mysql 上尝试了以下内容:

BEGIN;
INSERT INTO `tbl_users`(...) VALUES (...)
ROLLBACK();

它工作正常,这意味着问题不在我的 mysql 配置中。

但是当我在我的 Laravel 模型上尝试这个时:

public static function addNew($request, $department_id) 

    $result = array();

    $now = Carbon::now();

    DB::beginTransaction();

    //Checking for existing Order to set appropriate starting ID
    $result = DB::select("
        SELECT COUNT(`id`) AS 'count'
        FROM `tbl_consignmentorders`
    ")[0];

    if($result->count == 0)
        DB::update("ALTER TABLE `tbl_consignmentorders` AUTO_INCREMENT = 70000000001;");
    

    try 
        //INSERT
        DB::insert("
            INSERT INTO `tbl_consignmentorders`
            (`from`, `to`, `status`, `created_at`, `updated_at`) 
            VALUES 
            (?, ?, ?, ?, ?)",
            [
                $department_id,
                strtoupper($request->input('supplier')),
                'PENDING',
                $now,
                $now
            ]
        );
        //GET THE LAST ID INSERTED, NEEDED FOR NEXT INSERT
        $last_id = DB::select("
            SELECT 
                LAST_INSERT_ID() AS 'id'
            FROM `tbl_consignmentorders`;"
        )[0]->id;

        //CONSTRUCTING QUERY STRING FOR VALUES
        $values = '';
        $count = 0;
        foreach($request->input('item_id') as $item) 
            $values .= ',(' . $request->input('quantity')[$count] . ', ' . $last_id . ', ' . $item . ', ' . $request->input('item_price_id')[$count] . ' )';
            $count++;
        
        $values[0] = ' ';

        //INSERT TO DETAILS
        DB::insert("
            INSERT INTO `tbl_consignmentorderdetails`
            (`quantity`, `order_id`, `item_id`, `item_price_id`) 
            VALUES 
            $values;"
        );

        //INSERT TO TRANSACTION AUDIT
        DB::insert("
            INSERT INTO `tbl_transactions`
            (`type`, `reference_id`, `department_id`, `created_at`, `updated_at`) 
            VALUES 
            (?, ?, ?, ?, ?)",
            [
                'CONSIGNMENT ORDER',
                $last_id,
                $department_id,
                $now,
                $now
            ]
        );

        //COMMIT NOTHING FAILS
        DB::commit();
        $result = true;

     catch (\Exception $e) 
        //ROLLBACK SOMETHING IS WRONG
        DB::rollback();
        $result = $e->getMessage();
    

    return $result;

现在上面的代码在成功的时候可以正常工作,现在要产生错误,我会故意改变这部分代码:

    //GET THE LAST ID INSERTED, NEEDED FOR NEXT INSERT
    $last_id = DB::select("
        SELECT 
            LAST_INSERT_ID() AS 'id'
        FROM `tbl_consignmentorders`;"
    )[0]; //<--- I removed the ->id to return the whole object causing object to string error on the next query

现在正如预期的那样,它会转到 catch 块来传递错误消息,但是在错误之前执行的查询仍然存在于数据库中它不应该存在的地方。

【问题讨论】:

【参考方案1】:

大多数人对DB::rollback 不起作用的问题是他们没有首先启动DB::transaction 函数!

DB::rollback 仅在事务启动时有效

可以通过两种方式启动事务:

    在方法中使用 DB::transaction 函数

    DB::transaction(function () 
        DB::table('users')->update(['votes' => 1]);
    
        DB::table('posts')->delete();
    );
    

    通过在方法开始时手动启动事务,并且可能在调用外部 API 失败时,您调用 DB::rollback() 方法

    DB::beginTransaction();
    
    DB::rollBack();
    

【讨论】:

【参考方案2】:

如果你的系统使用多个数据库配置,你需要做这样的事情

DB::connection('database_config_2')->beginTransaction();
DB::connection('database_config_2')->rollback();
DB::connection('database_config_2')->commit();

希望对你有帮助!

【讨论】:

【参考方案3】:

我的错,

我使用DB::rollback(); 而不是DB::rollBack(); 大写B

【讨论】:

以上是关于Laravel DB::rollback() 不适用于事务处理的主要内容,如果未能解决你的问题,请参考以下文章

Laravel之事务与锁

laravel 控制器中使用 try catch

为啥 rake db:rollback 回滚三步?

yajra/laravel-datatables 搜索不适用于 laravel 5.4

yajra/laravel-datatables 搜索不适用于 laravel 5.7

Laravel 4 模型事件不适用于 PHPUnit