【发布时间】:2014-08-15 22:32:06
【问题描述】:
我正在构建 Web 应用程序 - 使用 php 和 mysql 的预订系统。系统将允许用户在某些设备上预留时间间隔(用户在该设备上工作的时间)。
我将这些保留的时间间隔称为槽。插槽存储在 mysql 数据库表中,如下所示:
CREATE TABLE IF NOT EXISTS `slot` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`start` int(11) unsigned DEFAULT NULL,
`end` int(11) unsigned DEFAULT NULL,
`uid` int(11) unsigned DEFAULT NULL,
`group` int(11) unsigned DEFAULT NULL,
`message` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`devices_id` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `start_2` (`start`),
UNIQUE KEY `end_2` (`end`),
KEY `index_foreignkey_slot_devices` (`devices_id`),
KEY `start` (`start`),
KEY `end` (`end`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci AUTO_INCREMENT=6997 ;
(这个表是redbean orm自动创建的,我还没优化)
因此,当用户创建预订时,会在此表中插入一个新行。在列中 开始,结束我保留每个预订开始和结束的 unix 时间戳。
要记住的另一件事是,应用程序允许不同的用户查看同一设备的不同时间表。例如:用户 A 有 6 分钟长的时间间隔,因此她可能会看到空闲槽 (12:00 - 12:06) 和空闲槽 (12:06 - 12:12),但用户 B 有 4 分钟长的时间间隔,所以他除其他外,还看到插槽 (12:04 - 12:08)。每个用户或用户组可以有不同的间隔持续时间。所以我必须确保当用户 A 和 B 都使用这些插槽发送请求时,其中只有一个成功。这让我想到了交易以及我的问题。
我这样做: - 开始交易 - 选择当天的所有时段 - 运行算法来检查选定的保留时隙和请求时隙之间的时间冲突 - 如果没有冲突,则在槽表中插入新行,否则向用户发出错误信号 - 提交
现在您知道并发运行时会发生什么。我是事务和 mysql 的新手,但尝试对其进行测试,我有理由相信在这种情况下仅仅进行事务是不够的,但我不确定。
所以我的问题是:如何在一个事务中正确选择、检查冲突和存储预订。
谢谢
【问题讨论】:
-
你试过
FOR UPDATE选项到SELECT吗?这会锁定您读取的所有记录,并且使用该选项的其他事务将无法读取它们,直到您的事务完成。 -
不是您问题的答案:
start或end(单独)上的唯一键显然是个坏主意。您可以预订同时开始或结束的不同设备。要么删除这些约束,要么将设备包含在密钥中(尽管这不足以避免重叠保留)。 -
@Barmar 不,我还没有尝试过,但它看起来链接了一个答案。您认为它会如何影响性能,因为我读它会锁定所有记录,因此其他请求将不得不等待。这是解决这个问题的唯一方法吗?
-
@jcaron 是的,我知道这还不够。正如我在问题中所说,我稍后会优化表结构,但谢谢我会记住你的笔记。
-
我自己没用过,但是我理解的方式是它只锁定被选中的记录,而不是表中的所有记录。因此,选择不相关记录的不同查询将不必等待。但是选择相同或重叠记录的查询将等待,这正是您想要的。
标签: php mysql transactions