我正在构建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的新手,但试图测试它,我有理由相信在这种情况下只是在交易中是不够的,但我不确定.

所以我的问题是:如何正确选择,检查冲突并在一个交易中存储预订.

谢谢

你需要的是锁定.确实“并非严格需要”交易.

您可以选择“悲观锁定”和“乐观锁定”.
关于这两种可能性中的哪一种取决于您并且必须进行评估的决定主要考虑:

>您拥有的并发级别
>数据库上必须原子操作的持续时间
>整个操作的复杂性

我将建议阅读这两个内容,以建立一个涉及的事情的想法:

> Optimistic vs. Pessimistic locking
> Optimistic locking in MySQL(这里有一些例子说明了如何不严格要求交易)

一个例子来解释得更好

这可能不是那么优雅,但它只是一个示例,显示了如何在没有事务的情况下完成所有操作(甚至没有UNIQUE约束).
需要做的是使用以下组合的INSERT SELECT statemet,并在执行后检查受影响的行数.
如果受影响的行数是1,那么它已经成功了(如果它是0)则发生了冲突而另一方已经获胜.

INSERT INTO `slot` (`start`,`end`,`uid`,`group`,`message`,`devices_id`)
SELECT @startTime,@endTime,@uid,@group,@message,@deviceid
FROM `slot`
WHERE NOT EXISTS (
    SELECT `id` FROM `slot`
    WHERE `start` <= @endTime AND `end` >= @startTime
    AND `devices_id` = @deviceid)
GROUP BY (1);

这是在没有事务和单个sql操作的情况下获得的乐观锁定的示例.

正如它所写的那样,它有一个问题,就是它必须在槽表中至少有一行才能工作(否则SELECT子句将始终返回一个空记录集,在这种情况下,如果没有,则不会插入任何内容evei碰撞.这有两种可能使它真正起作用:

>在表格中插入一个虚拟行,可能包含过去的日期
>重写所以主FROM子句引用任何至少有一行或更好的表创建一个小表(可能名为dummy),只有一列,只有一个记录,并重写如下(注意不再需要对于GROUP BY子句)

INSERT INTO `slot` (`start`,@deviceid
FROM `dummy`
WHERE NOT EXISTS (
    SELECT `id` FROM `slot`
    WHERE `start` <= @endTime AND `end` >= @startTime
    AND `devices_id` = @deviceid);

下面是一系列指令,如果您只是复制/粘贴显示实际的想法.我假设您将int字段上的日期/时间编码为一个数字,其中连接了日期和时间的数字.

INSERT INTO `slot` (`start`,`devices_id`)
VALUES (1008141200,1008141210,11,2,'Dummy Record',14)

INSERT INTO `slot` (`start`,`devices_id`)
SELECT 1408141206,1408141210,'Hello',14
FROM `slot`
WHERE NOT EXISTS (
    SELECT `id` FROM `slot`
    WHERE `start` <= 1408141210 AND `end` >= 1408141206
    AND `devices_id` = 14)
GROUP BY (1);

INSERT INTO `slot` (`start`,`devices_id`)
SELECT 1408141208,1408141214,14
FROM `slot`
WHERE NOT EXISTS (
    SELECT `id` FROM `slot`
    WHERE `start` <= 1408141214 AND `end` >= 1408141208
    AND `devices_id` = 14)
GROUP BY (1);

INSERT INTO `slot` (`start`,`devices_id`)
SELECT 1408141216,1408141220,14
FROM `slot`
WHERE NOT EXISTS (
    SELECT `id` FROM `slot`
    WHERE `start` <= 1408141220 AND `end` >= 1408141216
    AND `devices_id` = 14)
GROUP BY (1);

SELECT * FROM `slot`;

这显然是乐观锁定的极端示例,但最终效率非常高,因为所有操作都只使用一条sql指令,并且数据库服务器和PHP代码之间的交互很少(数据交换).此外,实际上没有“真正的”锁定.

……或者悲观锁定

相同的代码可以成为一个很好的Pessimistc锁定实现,只需使用显式的表锁定/解锁指令:

LOCK TABLE slot WRITE,dummy READ;

INSERT INTO `slot` (`start`,@deviceid
FROM `dummy`
WHERE NOT EXISTS (
    SELECT `id` FROM `slot`
    WHERE `start` <= @endTime AND `end` >= @startTime
    AND `devices_id` = @deviceid);

UNLOCK TABLES;

当然在这种情况下(悲观锁定)可以分离SELECT和INSERT,并在其间执行一些PHP代码.但是这段代码执行起来非常快(没有与PHP进行数据交换,没有中间的PHP代码),因此悲观锁的持续时间最短.保持悲观锁定尽可能短是一个关键点,以避免应用程序的速度减慢.

无论如何,您需要检查受影响的记录返回值的数量,以便知道它是否成功,因为代码实际上是相同的,因此您以相同的方式获得成功/失败信息.

在这里http://dev.mysql.com/doc/refman/5.0/en/insert-select.html他们说“MysqL不允许INSERT … SELECT语句的并发插入”所以它不应该需要pessimistic Lock但是无论如何这可能是一个很好的选择,如果你认为这将在MysqL的未来版本中发生变化.

我“乐观”,这不会改变;-)

php – MySQL事务:SELECT INSERT的更多相关文章

  1. HTML5、Select下拉框右边加图标的实现代码(增进用户体验)

    这篇文章主要介绍了HTML5、Select下拉框右边加图标的实现代码,深度美化页面增进用户体验效果,需要的朋友可以参考下

  2. 在Sierra上,Brew安装错误单独使用Xcode是不够的

    我正在尝试使用HomeBrewv1.3.8在运行xCodev9.1的MacOSXSerrav10.12.6上安装软件包.安装和错误是然后我运行命令表示软件更新服务器无法使用命令行工具包.我进入xCode,它表明安装了命令行工具.任何帮助将非常感激.西奥解决方法我去了AppleDeveloper网站并直接下载了命令行工具dmg.首先需要设置Apple帐户.命令行工具可在以下位置找到–https://

  3. iOS 10 Safari问题在DOM中不再包含元素

    使用此链接,您可以重现该错误.https://jsfiddle.net/pw7e2j3q/如果您点击元素并从dom中删除它,然后单击链接测试.你应该看到旧的元素弹出选择.是否有一些黑客来解决这个问题?解决方法我能够重现这个问题.问题是,每当您尝试删除其更改事件上的选择框时,iOS10都无法正确解除对选择框的绑定.要解决此问题,您需要将代码更改事件代码放在具有一些超时

  4. iOS Chrome上的HTML SELECT不显示“完成”选项

    我们在iOS上的Chrome中使用UI呈现时遇到问题,特别是HTMLSELECTDropDown元素.例:使用Safari,当您点击SELECT时,屏幕底部会打开一个微调器–您可以点击完成以选择您的选择并返回到表单.但是,当您在iOS上的Chrome中加载完全相同的页面时,不会显示“完成”.用户必须选择他们的选择,然后点击UI上的其他位置返回到表单.非常不直观,用户感觉好像SELECT没有用.有人有解决方案吗?

  5. 安装命令行工具Xcode 5

    我已经尝试过并尝试过但我仍然无法解决问题.我正在尝试安装PebbleSDK1.12并安装Xcode5的命令行工具.每次我在终端尝试xcode-select–install时,我都会收到“无法安装软件,因为它目前在软件更新服务器中不可用”我试图重新安装Xcode,但是没有用.当我进入Xcode-preferences-downloads时,没有命令行工具的部分.我也试过从开发者网站安装它们但无济于事.下载看起来正确,然后我去Xcode看到首选项,并没有列出命令行工具.你们都能提出什么建议吗?

  6. ios – xcodebuild相当于Xcode的“产品&gt;构建&gt;测试”

    我正在尝试编写一个脚本,将iOS应用程序提交给AppThwack(一个“真正的设备”UI测试服务).他们的指导是使用XcodeGUI,并使用BuildFor>Xcode产品菜单中的测试选项.这是有效的,但我无法将其转换为xcodebuild等效项.更一般地说,我们如何确定Xcode传递给xcodebuild的什么参数(假设它使用该工具).解决方法现在可以从Xcode8开始(在写作时在beta版).

  7. xcode – 在REPL中创建目标Swift AST上下文时出错((null))

    在这里,我已经看到有关这个错误的几个的问题,但是没有一个提出的解决方案适用于我.这是我得到的这可能是也可能没有发生在我发出一些我不记得的命令之后.奇怪的是,如果我卸载Xcode,REPL开始正常工作.但是,如果我重新安装Xcode,错误就会回来.我在Xcode7.2.1,顺便说一句.思考?

  8. IOS设备问题与HTML表单输入(type = text)

    所以我有一个HTML登录表单与两个字段:电子邮件和密码.这些可以在除iOS设备之外的任何设备的浏览器上轻松填充.在IOS领域几乎不能关注焦点,一旦焦点,键盘弹出,我开始打字,但实际上没有填充.我已经尝试过Chrome和safari,仍然得到相同的结果.字段保持黑色.Bellow是我的格式如何格式化:请帮助!

  9. 从iOS应用程序发送帖子到PHP脚本不工作…简单的解决方案就像

    我之前已经做了好几次了但是由于某些原因我无法通过这个帖子…我尝试了设置为_POST且没有的变量的PHP脚本……当它们未设置为发布时它工作精细.这是我的iOS代码:这里是PHP的一大块,POST变量不在正确的位置?我想这对于更有经验的开发人员来说是一个相当简单的答案,感谢您的帮助!解决方法$_POST是一个数组,而不是一个函数.您需要使用方括号来访问数组索引:

  10. 我在哪里可以获得XCode的10.6 SDK

    我有SNowLeopard的测试版,我从DVD上安装了XCode,但它只安装了10.5和10.4SDK.我需要针对10.6构建以验证Apple的错误.解决方法ADCMemberSite.登录并选择下载.如果您是Premier或Select会员,那应该是您可以找到它的地方.如果您不是Premier或Select会员,您将看不到它.

随机推荐

  1. PHP个人网站架设连环讲(一)

    先下一个OmnihttpdProffesinalV2.06,装上就有PHP4beta3可以用了。PHP4给我们带来一个简单的方法,就是使用SESSION(会话)级变量。但是如果不是PHP4又该怎么办?我们可以假设某人在15分钟以内对你的网页的请求都不属于一个新的人次,这样你可以做个计数的过程存在INC里,在每一个页面引用,访客第一次进入时将访问时间送到cookie里。以后每个页面被访问时都检查cookie上次访问时间值。

  2. PHP函数学习之PHP函数点评

    PHP函数使用说明,应用举例,精简点评,希望对您学习php有所帮助

  3. ecshop2.7.3 在php5.4下的各种错误问题处理

    将方法内的函数,分拆为2个部分。这个和gd库没有一点关系,是ecshop程序的问题。会出现这种问题,不外乎就是当前会员的session或者程序对cookie的处理存在漏洞。进过本地测试,includes\modules\integrates\ecshop.php这个整合自身会员的类中没有重写integrate.php中的check_cookie()方法导致,验证cookie时返回的username为空,丢失了登录状态,在ecshop.php中重写了此方法就可以了。把他加到ecshop.php的最后面去就可

  4. NT IIS下用ODBC连接数据库

    $connection=intodbc_connect建立数据库连接,$query_string="查询记录的条件"如:$query_string="select*fromtable"用$cur=intodbc_exec检索数据库,将记录集放入$cur变量中。再用while{$var1=odbc_result;$var2=odbc_result;...}读取odbc_exec()返回的数据集$cur。最后是odbc_close关闭数据库的连接。odbc_result()函数是取当前记录的指定字段值。

  5. PHP使用JpGraph绘制折线图操作示例【附源码下载】

    这篇文章主要介绍了PHP使用JpGraph绘制折线图操作,结合实例形式分析了php使用JpGraph的相关操作技巧与注意事项,并附带源码供读者下载参考,需要的朋友可以参考下

  6. zen_cart实现支付前生成订单的方法

    这篇文章主要介绍了zen_cart实现支付前生成订单的方法,结合实例形式详细分析了zen_cart支付前生成订单的具体步骤与相关实现技巧,需要的朋友可以参考下

  7. Thinkphp5框架实现获取数据库数据到视图的方法

    这篇文章主要介绍了Thinkphp5框架实现获取数据库数据到视图的方法,涉及thinkPHP5数据库配置、读取、模型操作及视图调用相关操作技巧,需要的朋友可以参考下

  8. PHP+jquery+CSS制作头像登录窗(仿QQ登陆)

    本篇文章介绍了PHP结合jQ和CSS制作头像登录窗(仿QQ登陆),实现了类似QQ的登陆界面,很有参考价值,有需要的朋友可以了解一下。

  9. 基于win2003虚拟机中apache服务器的访问

    下面小编就为大家带来一篇基于win2003虚拟机中apache服务器的访问。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  10. Yii2中组件的注册与创建方法

    这篇文章主要介绍了Yii2之组件的注册与创建的实现方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下

返回
顶部