间歇性锁定等待超时 Laravel 数据库事务(重试 5 次)

Intermittent Lock Wait Timeout Laravel DB Transaction (with 5 retries)

我们一直遇到间歇性锁定超时错误(大约每天 1-2 次,共约 250 次)。

结帐时,我们会获取所有用户详细信息、保存订单、处理任何付款,然后更新订单。我认为可能是二次更新导致的。

我们的代码示例(不完全相同但足够接近):

DB::transaction(function () use ($paymentMethod, $singleUseTokenId, $requiresPayment, $chargeAccount) {
    // create order locally
    $order = Order::create([
        'blah' => $data['blah'],
    ]);

    // handle payment
    $this->handlePayment();

    // update order with new status (with a secondary transaction for safety)
    DB::transaction(function () use ($order) {
        $order->update([
            'status' => 'new status',
        ]);
    }, 5);

}, 5); // Retry transaction 5 times - this reduced the lock timeout errors a lot

我们得到的间歇性错误是(实际值已删除):

SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction (SQL: insert into `orders` (`user_id`, `customer_uuid`, `type_uuid`, `status_uuid`, `po_number`, `order_details`, `cart_identifier`, `cart_content`, `cart_sub_total`, `cart_tax`, `cart_grand_total`, `payment_type_uuid`, `shipping_address`, `uuid`, `updated_at`, `created_at`) 

我已经阅读了很多,有人说增加超时(似乎是一种解决方法)、乐观锁定(我认为事务已经这样做了)和其他事情。

据我从数据库面包屑中可以看出,订单创建有时需要很长时间(例如,在 3 秒看到一个,另一个在 23 秒看到,由于某种原因通常是 50 毫秒插入),然后其他事情发生了,它尝试更新订单,但该行仍被 create() 锁定。

备注:

有什么建议吗?

解决:订单uuid没有主键。非常愚蠢的错误。导致 InnoDB 基本上为索引创建一个 6 字节的键。并锁定连续插入,然后更新..

如果您看到 "lock wait timeout" 个错误,请查看 其他 个交易。特别有害的是长 运行 交易。您可以在 SHOW ENGINE INNODB STATUS\G 中找到它们。攀登 InnoDB 历史列表表明也有一些。目前 运行 长交易将在 information_schema.INNODB_TRX.

中列出

请注意,如果事务获取了独占锁,则直到事务结束才会释放它,而不是查询结束。

首先,排除长 运行 查询。例如,慢速 UPDATE 将为其执行时间持有锁。

在相当快地完成所有查询后,请检查您的交易。使它们尽可能短。客户经常打开一个事务,执行一两个查询,然后转到第三方 API 调用或做其他繁重的工作并保持事务打开。与此同时,其他交易将获得 "Lock wait timeout".