【问题标题】:MySQL atomic operations and table lockingMySQL 原子操作和表锁定
【发布时间】:2012-07-01 23:18:47
【问题描述】:

我有一个网站,用户可以在其中购买门票,但门票数量通常是有限的,而且很快就能买到。我正在尝试实现一个托管系统,以便用户可以单击他们想要 x 数量的票,此时我会将它们置于托管状态。这样他们就可以在几分钟内输入信用卡信息并完成购买。

我有三个相关的表格:事件、门票和托管。事件表中的一行描述了事件本身,包括可用门票的最大数量。

门票表包含以下内容:

user_id:购买门票的用户

number_of_tickets:他们购买了多少张门票

event_id:相关事件

托管表包含以下内容:

user_id:正在购票的用户

number_of_tickets:他们想要多少张门票

event_id:相关事件

目前,我执行三个 MySQL 查询,一个查询最大票数,一个查询已售票数,一个查询已托管票数。然后我计算:

$remaining_tickets = $max_tickets - $tickets_sold - $tickets_in_escrow;
if ($remaining_tickets >= $tickets_desired)
{
    beginEscrow($user_id, $event_id, $tickets_desired);
}
else
{
    echo "Error:  not enough ticket remain.";
}

我的问题是多个用户可能同时执行此代码。如果一个用户在 另一个用户已经阅读了已在托管中的门票数量之后打电话给beginEscrow,那么我可能会超卖该节目。

我正在为我的表使用 InnoDB 引擎,并且我已经阅读了如何使用 SELECT .... FOR UPDATE 锁定单行,但我没有更新单行。 beginEscrow 函数只会在托管表中插入一个新行。我通过读取具有正确事件 ID 的所有行并将每行中的票数相加来计算 $tickets_in_escrow

也许我做错了?

我需要锁定整个表吗?

我不能成为第一个编写票务托管系统的人。我已经用谷歌搜索了自己,试图找到一些关于这种事情的教程,但被淘汰了。任何想法都会有所帮助。

谢谢!

【问题讨论】:

    标签: mysql locking innodb atomic escrow


    【解决方案1】:

    你的设计非常接近,但还不够。

    首先,您的活动表需要保存您的活动仍然可用的门票数量(除了您想要的任何其他门票)。

    其次,您的托管表需要有一个 DATETIME 列来指示托管何时到期。每当门票进入托管时,您都需要设置该值。

    三、入票交易需要

    1. 锁定事件行。
    2. 阅读可用票列。 (如果没有足够的可用则中止)
    3. 在托管表中插入一行
    4. 更新事件行以减少可用门票列。
    5. 解锁事件行。

    第四,完成销售的动作需要删除escrow行并插入sold-ticket行。这并不难。

    第五,您需要进行托管清理操作。这需要查找所有已过期(过去有过期日期)的托管行,并且对于每一行:

    1. 锁定对应的事件行。
    2. 从托管表中读取托管票的数量
    3. 删除托管表行。
    4. 更新活动行以增加可用门票列。
    5. 解锁事件行。

    诀窍是以正确联锁的方式维护可用门票的数量,这样用户之间的竞争条件就不会过度销售您的活动。

    【讨论】:

    • 所以换句话说,所有的托管票据计数应该在单个表中的一行中,而不是托管表中的行的总和。我明白这是有道理的。谢谢。
    • 实际上,所有的票据计数——可用的、托管的和已售出的,都应该在单个表中的单个行的单个列中。该列达到零,没有更多席位可供出售。但你有这个想法。
    • 在 StackOverflow 上,如果答案对您有帮助,您应该点击绿色复选标记接受它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 2022-01-12
    • 2012-07-31
    • 1970-01-01
    • 2014-10-30
    相关资源
    最近更新 更多