Laravel 5.3 DB:transaction 正在提交甚至一些查询失败

Laravel 5.3 DB:transaction is committing even some queries failed

我有一个用于基本用户信息的用户模型,然后是一个用于将角色与用户相关联的角色模型和角色用户模型。在用户编辑表单上,可以为该用户添加其他角色。因此,这里有两个数据库操作在 DB::transaction、

内完成
1) Update User info into User model
2) Add role to user

问题是,如果 "Add role to user" 失败,它不会回滚已成功更新的 "User" 模型中的更改。

这是我的示例代码-

在控制器中:

$response =
DB::transaction(function() use($user_data, $input) {
    //Update changes in basic user info using "User" Model
    $response = User::updateUser($user_data['user']);

    if ($response->status===FALSE) {//not updated
        return $response;
    }
    if (!empty($user_data['roles'])) {
        $roles = [];
        foreach ($user_data['roles'] as $role) {
            $roles[] = ['role_id' => $role, 'user_id' => $user_data['user']['id'], 'created_by' => $this->curr_user->id, 'updated_by' => $this->curr_user->id];
        }
    //Add new roles to the user using "RoleUser" Model
        $response3 = RoleUser::createRoleUser($roles);
        if ($response3->status===FALSE) {//failed to add
            return $response3;
        }                            
    }

    return $response;
}, 5);

//RoleUser模型中createRoleUser方法的来源

try {
    DB::table($table)->where('id', $id)->update($changes);
} catch (\Illuminate\Database\QueryException $qe) {
    return (object) ['status' => FALSE, 'error' => $qe->errorInfo];
} catch (\Exception $e) {
    return (object) ['status' => FALSE, 'error' => [$e->getCode(), 'non-DB', $e->getMessage()]];
}
return (object) ['status' => TRUE, 'data' => $changes + ['id' => $id]];

//RoleUser模型中createRoleUser方法的来源

try {
    $new_rec_id = DB::table('role_users)->insertGetId($new_data);
    $new_rec = FALSE;
    if ($new_rec_id) {
        $new_rec = DB::table($table)->where('id', $new_rec_id)->first();
    }
} catch (\Illuminate\Database\QueryException $qe) {
    return (object) ['status' => FALSE, 'error' => $qe->errorInfo];
} catch (\Exception $e) {
    return (object) ['status' => FALSE, 'error' => [$e->getCode(), 'non-DB', $e->getMessage()]];
}
return (object) ['status' => TRUE, 'data' => $new_rec];

您必须从事务闭包中抛出异常,以便事务触发回滚。如果没有抛出异常,事务将提交。

记住这一点,这意味着对 transaction 函数的调用需要包装在 try/catch 中,因为处理回滚的代码将在回滚后重新抛出异常要处理的应用程序代码。

因此,您的代码将类似于:

try {
    $response = DB::transaction(function() use($user_data, $input) {
        //Update changes in basic user info using "User" Model
        $response = User::updateUser($user_data['user']);

        if ($response->status===FALSE) {//not updated
            // throw exception to trigger rollback
            throw new \Exception($response->error);
        }
        if (!empty($user_data['roles'])) {
            $roles = [];

            foreach ($user_data['roles'] as $role) {
                $roles[] = ['role_id' => $role, 'user_id' => $user_data['user']['id'], 'created_by' => $this->curr_user->id, 'updated_by' => $this->curr_user->id];
            }

            //Add new roles to the user using "RoleUser" Model
            $response3 = RoleUser::createRoleUser($roles);
            if ($response3->status===FALSE) {//failed to add
                // throw exception to trigger rollback
                throw new \Exception($response3->error);
            }                            
        }

        // return without exception to trigger commit
        return $response;
    }, 5);
} catch (\Exception $e) {
    echo 'uh oh: '.$e->getMessage();
}