鍍金池/ 問答/PHP/ PHP用laravel的隊(duì)列寫搶紅包后的資產(chǎn)處理是總是出現(xiàn)鎖死

PHP用laravel的隊(duì)列寫搶紅包后的資產(chǎn)處理是總是出現(xiàn)鎖死

現(xiàn)在是一共有五條隊(duì)列處理資產(chǎn),當(dāng)然一個(gè)紅包的領(lǐng)取記錄肯定是在一個(gè)隊(duì)列里處理的。

根據(jù)錯(cuò)誤日志,是下面的在讀鎖資產(chǎn)那一部分出現(xiàn)的鎖死,但是找了幾天不知道什么原因

        DB::beginTransaction();
        // 讀鎖資產(chǎn)
        $table = 'assets_' . strtolower($coin->name);
        $asset = DB::table($table)->select('id', 'lock_num', 'over_num', 'updated_at')->where('user_id', $user_id)->lockForUpdate()->first();
        if (!$asset) {
            DB::rollBack();

            return error(Code::ASSET_ABNORMAL);
        }
        // 余額變更
        $tmp = ['updated_at' => time()];
        if (isset($value['over']) && is_numeric($value['over']) && $value['over'] != 0) {
            if (($asset->over_num + $value['over']) < 0) {
                DB::rollBack();

                return error(Code::NOT_ENOUGH);
            }
            $tmp['over_num'] = bcadd($asset->over_num, $value['over'], $number_float);
        }
        // 凍結(jié)變更
        if (isset($value['lock']) && is_numeric($value['lock']) && $value['lock'] != 0) {
            if (($asset->lock_num + $value['lock']) < 0) {
                DB::rollBack();

                return error(Code::NOT_ENOUGH);
            }
            $tmp['lock_num'] = bcadd($asset->lock_num, $value['lock'], $number_float);
        }
        if (!isset( $tmp['over_num']) && !isset($tmp['lock_num'])) {
            DB::rollBack();
            
            return error(Code::SYSTEM_BUSY);
        }
        if (!DB::table($table)->where('id', $asset->id)->update($tmp)) {
            DB::rollBack();

            return error(Code::SYSTEM_BUSY);
        }

        DB::commit();
回答
編輯回答
久舊酒

一般情況下我不會(huì)這樣寫:

$asset = DB::table($table)->select('id', 'lock_num', 'over_num', 'updated_at')->where('user_id', $user_id)->lockForUpdate()->first();

而是:

$asset = DB::table($table)->select('id', 'lock_num', 'over_num', 'updated_at')->where('user_id', $user_id)->first();
if(is_null($asset)){
    //error信息
}
DB::table($table)->select('id', 'lock_num', 'over_num', 'updated_at')->where('id',$id)->lockForUpdate()->first();

用主鍵鎖,一定就是那一行。

2018年7月6日 16:08