Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql SQL表锁定竞争条件-选择然后插入_Mysql_Sql - Fatal编程技术网

Mysql SQL表锁定竞争条件-选择然后插入

Mysql SQL表锁定竞争条件-选择然后插入,mysql,sql,Mysql,Sql,MariaDB/MySQL有一个很好的锁定问题 服务器正在重新组装多部分SMS消息。消息以分段的方式到达。具有相同“smsfrom”和“uniqueid”的段是同一消息的一部分。段的段号从1开始到“segmenttotal”。当消息的所有部分都到达时,消息就完成了。我们有一个待重新组装的不匹配段表,如下所示: CREATE TABLE frags ( smsfrom TEXT, uniqueid VARCHAR(32) NOT NULL, sms

MariaDB/MySQL有一个很好的锁定问题

服务器正在重新组装多部分SMS消息。消息以分段的方式到达。具有相同“smsfrom”和“uniqueid”的段是同一消息的一部分。段的段号从1开始到“segmenttotal”。当消息的所有部分都到达时,消息就完成了。我们有一个待重新组装的不匹配段表,如下所示:

    CREATE TABLE frags (
       smsfrom TEXT,
       uniqueid VARCHAR(32) NOT NULL,
       smsbody TEXT,
       segmentnum INTEGER NOT NULL,
       segmenttotal INTEGER NOT NULL);
当一个新的细分市场进入时,我们在交易中

   SELECT ... FROM frags WHERE smsfrom = % AND uniqueid = %;
这让我们了解到目前为止收到的所有片段。如果新的 加上这些有所有的段号,我们有一个完整的信息。 我们发送消息进行进一步处理,并删除相关片段。好的

如果不是所有的片段都已到达,我们将插入刚得到的片段。“自动提交”处于禁用状态,因此这两个操作都是事务的一部分。顺便提一下,InnoDB引擎

这有一个竞赛条件。对于两段消息,两段同时进入,并由单独的进程处理。进程A进行选择,但未找到任何内容。进程B进行选择,但未找到任何内容。进程A插入段1,没有问题。过程B插入段2,没有问题。现在我们被卡住了——所有的部分都在表中,但我们没有注意到。因此,信息永远停留在那里。(实际上,我们每隔几分钟进行一次清理,以删除旧的不匹配的内容,但现在忽略此操作。)

那怎么了?选择“不锁定行”,因为它们找不到任何内容。 我们需要一个尚未存在的行上的行锁。将更新添加到选择中没有帮助;没什么要锁的。也不会锁定在共享模式下。即使使用可序列化的事务类型也无济于事,因为这只是共享模式下的全局锁

好的,假设我们先进行插入,然后进行选择,看看是否有所有的线段。进程A插入1,没有问题。进程B插入2,没有问题。进程A进行选择,只看到1。进程B进行选择,只看到2个。这就是可重复阅读语义。不好

蛮力方法在执行任何操作之前都是一个锁表。这应该是可行的,尽管这很烦人,因为我正在处理一个涉及其他表的事务,而锁表意味着提交

在每次插入后进行提交可能有效,但我不能完全确定

有更优雅的解决方案吗?

为什么没有

1) 过程1。插入到您的frag表中。没有别的了

插入。。。。 承诺

2) 过程2 这将通过查找完整的多部分SMS

按smsfrom、unique、unique having count()=段总数从frags组中选择smsfrom、uniqueid、uniqueid、count()

将它们移到新表中

从碎片中删除,其中smsfrom=和unique=


承诺

正如我在上面所写的,我最终做了以下工作:

INSERT  ... -- Insert new fragment.
COMMIT
SELECT ... FROM frags WHERE smsfrom = % AND uniqueid = % FOR UPDATE;
检查SELECT是否返回了完整的片段集。如果是,重新组装并处理消息,然后

DELETE ... FROM FRAGS WHERE smsfrom = % AND uniqueid = %;
提交和更新都是必需的。需要提交,以便每个进程都能看到来自另一个进程的任何插入。在SELECT行上需要FOR UPDATE来锁定所有片段,直到完成删除。否则,两个进程可能会在SELECT和Remoble中看到完整的片段集,并对消息进行两次处理


这对于一个单表问题来说非常复杂,但似乎有效

如果您在提交后将其他段的检查移动到?需要一些方法来确保进程A和进程B不同时处理消息。我最后做了类似的事情—插入、提交,然后在一个进程中选择。必须对另一个select执行select FOR UPDATE以获得行锁,否则两个进程都可以找到组装好的消息,并且它将被处理两次。很高兴听到这有助于。。。。我不会问您如何处理在成功重新组装原件后到达的OOB(带外)多部分消息:)-您可能需要对它们进行说明,或者简单地删除超过2天的任何内容-这取决于您的业务需求。