Laravel DB::rollback() 不适用于交易流程

Laravel DB::rollback() doesn't work for transaction processes

首先我的引擎是 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 块以传递错误消息,但是,在错误之前执行的查询仍然存在于数据库中,而它不应该存在。

我错了,

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

大多数人遇到 DB::rollback 不工作的问题是他们没有先启动 DB::transaction 功能!

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

可以通过两种方式启动交易:

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

    DB::transaction(function () {
        DB::table('users')->update(['votes' => 1]);
    
        DB::table('posts')->delete();
    });
    
  2. 通过在方法开始时手动启动事务并且可能在调用外部 API 失败时调用 DB::rollback() 方法

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

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

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

希望对您有所帮助!