My SQL 5.6-如何防止读取前一个SQL语句选择的行以及给定列中共享重复值的任何其他行

问题描述 投票:0回答:1

我有一个非常特殊且非常复杂的需求,以防止来自来自不同服务器的大量并发(同一秒,有时是相同的毫秒)请求的读取](准确地说,它们是AWS Lambdas)在名为Hobby_ideas_articles的表上。

设置:

  • mySQL 5.6

  • 在无AWS Aurora服务器的MySQL上(默认情况下,自动提交处于关闭状态)

我当然阅读了很多关于行锁的文章,并认为它们可能是解决方案的一部分,但我认为我不在基本的select...for update案例中。

我的表是Hobby_ideas_articles,并具有诸如以下的记录:

hobby_idea_article_id= 1,
hobby_id = 6
url= 'http://exo.example.com',
author = '[email protected]'

hobby_idea_article_id= 2,
hobby_id = 3
url= 'http://exo.example2.com',
author = '[email protected]'

hobby_idea_article_id= 3,
hobby_id = 7
url= 'http://exo.example3.com',
author = '[email protected]'

并且我还有另一个名为Past_Customer_sent_messages的表,其中的记录如下:

past_customer_sent_message_id = 5
hobby_id = 7,
customer_id = 4,
recipient = "[email protected]",
sent_at= "2019-09-10 00:00:00"

past_customer_sent_message_id = 6
hobby_id = 999,
customer_id = 4,
recipient = "[email protected]",
sent_at= "2019-09-18 00:00:00"

past_customer_sent_message_id = 7
hobby_id = 999,
customer_id = 4,
recipient = "[email protected]",
sent_at= "2019-07-18 00:00:00"

我今天有一个正常运行的SQL语句,基于2个输入(hobby_idcustomer_id]] >>(每个lambda的值不同),将使用给定的Hobby_ideas_articles来获取所有hobby_id,并且排除/过滤最近发送给作者的消息时(由任何客户在x天内,由特定customer_id在y小时内)发送的任何结果(以了解有关这些条件/限制的详细信息:[C0 ])。

MySQL - Select data with a JOIN but with WHERE clauses applying to complex and distinct perimeters

举例来说:

  • 在上午10:05:03,lambda将执行SELECT hia.hobby_idea_article_id, hobby_id, url, author, ces.sent_at FROM Hobby_ideas_articles hia LEFT JOIN Past_Customer_sent_messages ces ON hia.author = ces.recipient WHERE hia.hobby_id = HOBBY_ID_INPUT_I_HAVE AND hia.author IS NOT NULL AND hia.author NOT IN ( SELECT recipient FROM Past_Customer_sent_messages WHERE ( customer_id = CUSTOMER_ID_INPUT_I_HAVE AND sent_at > DATE_SUB(NOW(), INTERVAL 30 DAY) ) OR ( sent_at > DATE_SUB(NOW(), INTERVAL 3 HOUR ) ) ) GROUP BY hia.author ORDER BY hia.hobby_idea_article_id ASC LIMIT 20 hobby_idea_article_id= 4的语句>
  • 在10:05:04 am,仅在不到一毫秒后,另一个lambda将执行customer_id= 7hobby_idea_article_id= 12的语句...等等...
  • 唯一的“业务逻辑”保证是我永远不会有两个具有相同输入对(customer_id= 8hobby_id)的并发lambda”。

因此,当前的SO问题是关于[[如何确保客户在处理来自大量并发lambda的请求时,永远不会向同一收件人发送两封快速电子邮件(一封在另一封之后几秒钟) ?问题的说明是:

  • 在上午10:05:03,lambda执行customer_idhobby_id= 4 3的SQL语句并检索这些数据:

    hobby_idea_article_id = 2,hobby_id = 4url ='customer_id=',作者='[email protected]'

    hobby_idea_article_id = 3,hobby_id = 4url ='http://exo.example2.com',作者='[email protected]'

    这意味着我将在几秒钟后发送http://exo.example3.com[email protected]电子邮件(由另一个lambda执行,该lambda负责处理传递有数据的电子邮件)]]

    • [上午10:05:03,

      以相同的秒数/毫秒执行的并行lambda

      执行[email protected]hobby_idea_article_id= 4的SQL语句(实际上,我可以有8个客户想要关于嗜好的想法“以id = 4进行钓鱼!)。此lambda 检索大致相同的数据
    • 作为第一个lambda(如您在SQL语句上看到的,customer_id= 7输入仅用于过滤出已经获得作者的作者举例来说,假设由于客户12天前已经用customer_id 7通知了john,所以它过滤掉了john,所以这里检索到的数据是:] >customer_id=
    这意味着我将在几秒钟后向[email protected]发送电子邮件(由传递了此数据的另一个lambda执行)

    这里是问题:[email protected]将收到2封快速电子邮件

    ,但我绝对不想允许这种事情。我在当前SQL语句中拥有的保护(请参阅条件1和2 hobby_idea_article_id= 3, hobby_id = 4 url= 'http://exo.example3.com', author = '[email protected]' 中的说明),仅当我可以使用已在Past_Customer_sent_messages上发送过的有关电子邮件的持久性信息时,才可以防止这些重复的快速电子邮件,但是由于这种情况如此接近/因此,与此同时,第二个lambda不会看到已经(或更确切地说,几秒钟后另一个lambda将“将要”发送)消息到here。我需要确保第二个lambda不会输出author = eric的hobby_idea,以防止出现此类重复发送电子邮件的情况。

    我有两个想法解决方案,但是我认为第二个解决方案更好,因为第一个解决方案有问题。

1。解决方案1-通过[email protected]使用行锁吗?

这样,当第一个lambda到达SQL时,它将阻止对SQL查询输出行的所有行进行读取,如果我正确理解的话,它们将对随后的任何SELECT都是“不可见的”。这意味着,如果第二个lambda并发到达,则甚至不会考虑/发现第一个lambda的SQL语句行的结果!

阅读后,我考虑过要在

transaction

中进行此操作,并移动状态为“ currently_locked_for_emailing”的第一个SQL语句的结果的所有hobby_idea_articles,并分配值select ...for update,然后进行解锁通过“提交”交易。然后,当我实际从另一个lambda发送电子邮件时,并且仅在已在Past_Customer_sent_messages表上的数据库上实际存储/写入了有关该电子邮件的数据**之后,我才将状态更改为“ currently_locked_for_emailing”到true **。

在这种情况下,行锁对我很有用,以确保在我更改/更新状态(这几毫秒)时,确保没有其他lambda可以读取数据。

下面的此SQL语句是否有效?注意事务和'currently_locked_for_emailing'

上的新WHERE子句

false

1.1您能帮我解决上面的SQL代码吗?

1.2放置锁后将-- (A) start a new transaction START TRANSACTION; -- (B) Get the latest order number SELECT hia.hobby_idea_article_id, hobby_id, url, author, ces.sent_at FROM Hobby_ideas_articles hia LEFT JOIN Past_Customer_sent_messages ces ON hia.author = ces.recipient WHERE hia.hobby_id = HOBBY_ID_INPUT_I_HAVE AND hia.author IS NOT NULL AND hia.author NOT IN ( SELECT recipient FROM Past_Customer_sent_messages WHERE ( customer_id = CUSTOMER_ID_INPUT_I_HAVE AND sent_at > DATE_SUB(NOW(), INTERVAL 30 DAY) ) OR ( sent_at > DATE_SUB(NOW(), INTERVAL 3 HOUR ) ) ) AND # NEW CLAUSE ON currently_locked_for_emailing # THAT GOES ALONG WITH THE ROW LOCK STRATEGY hia.currently_locked_for_emailing = false GROUP BY hia.author ORDER BY hia.hobby_idea_article_id ASC LIMIT 20 # ADD THE NEW FOR UPDATE FOR THE ROW LOCK FOR UPDATE -- (C). Update the column `currently_locked_for_emailing` to `true` UPDATE Hobby_ideas_articles SET currently_locked_for_emailing = true WHERE ############### how to say do it for all the same rows which are the result of the previous SQL statement on above (see (B) -- (D) commit changes COMMIT; 更新为currently_locked_for_emailing,但之前如何做是感觉不对?

1.3另外,我不知道如何断言'请将true更改为currently_locked_for_emailing

对于所有行,这是上面(A)中SQL的结果] >>]1.4如何“解锁”交易?确实在更新了current_locked_for_emailing状态之后,我就可以解锁ti以进行读取和写入,但是该怎么做?确实,我不想等待与服务器的连接结束。请您确认锁一旦到达(D)上的事务“ COMMIT”,便会立即将其删除?

1.5是正确的说法,就是上面的代码仅锁定作为SELECT结果输出的所有行,而不锁定整个表中的所有行?如果是,是否表示通过使用

LIMIT 20

,它将仅锁定结果的20行,而不是所有匹配的行(我的意思是对应于WHERE子句),这很好,但是我d想要确定这一点。
1.6我读了很多其他文章(true,要使行锁起作用,必须绝对有一个索引...一个人甚至说here”“我自己的测试表明,使用在未索引列上的过滤器将导致整个表的锁定,而在已索引列上的过滤器将导致过滤的行锁定的预期行为。”是真的,那我应该说什么呢,这不像我的where是在1或2列上简单的...在我的所有where子句列上的索引都会很复杂吗?]]

2。解决方案2-对select ... update进行补充,因为即使我正确地获得了1.,我仍然有一个重要的问题:

如果我正确理解“行锁”会锁定SELECT结果中的所有行,那么这里就是问题所在。

但是我需要的真正的锁定不仅是针对选择结果的行,而且我需要将行锁定设置为作者具有与SELECT结果内的行相同值的任何行] >

[让我通过一个示例解释为什么我使用与1相同的数据。

  • 在上午10:05:03,lambda为

    hobby_id = 4

    customer_id = 3执行SQL语句并检索这些数据:here
    ...这意味着我将在几秒钟后发送hobby_idea_article_id= 2,
    hobby_id = 4
    url= 'http://exo.example2.com',
    author = '[email protected]'
    
    hobby_idea_article_id= 3,
    hobby_id = 4
    url= 'http://exo.example3.com',
    author = '[email protected]'
    [email protected]电子邮件(由传递了此数据的另一个Lambda执行)

    使用行锁解决方案1.,我们现在知道第二个lambda将无法通过hobby_idea_article_id 2和3选择上面的前2个记录(很酷!),因为它会:
    • 如果事情非常同时发生,则遇到行锁(这些行对他都是不可见的,
    • OR因为因为它们现在具有[email protected]而不会选择它们(请参见新的SQL语句WHERE子句'currently_locked_for_emailing'= true
  • OR
  • ,因为已发送电子邮件,并且我们已经保留了已通过Past_Customer_sent_messages发送的事实。

    ...但是我还有一个大问题。

    • [上午10:05:03,第二个lambda执行

      hobby_id = 9

    的SQL语句(这是另一个爱好,这是我的问题的核心)和customer_id = 13 并检索这些数据:currently_locked_for_emailing = 'false'
    正如您所看到的,因为这里有一个特殊的情况,行锁定的策略不起作用:确实

    我希望第二个lambda不能获取此数据

    ,因为作者是相同的([ C0]),但是它没有被第一个SQL语句锁定,也没有分配hobby_idea_article_id= 4, hobby_id = 9 //the hobby_id is DIFFERENT from the one above url= 'http://exo.example3.com', author = '[email protected]'//but the email recipient is still [email protected] !!!! ,因为第一个SQL语句有一个[email protected]的WHERE子句...但是这里是一个不同的currently_locked_for_emailing= true!因此该行从未被锁定过,因此该行hobby_id=4将被抓取,并且冒着在几毫秒内给同一收件人发送电子邮件的风险。所以我不确定如何执行此操作,但是**也许我需要像组合行锁之类的东西,或者**两个行锁****(不确定如何工作)会放行锁'(直到我用hobby_id更新)::>

      1. 首先是作为SQL语句SELECT的结果行的行]
    1. 而且还有hobby_idea_article_id= 4的任何其他行,该行与SELECT的结果行之一具有相似的“作者”值在第1行和第2行上,我都将应用事务处理策略,并将currently_locked_for_emailing = true设置为Hobby_ideas_articles(直到发送了实际的电子邮件,并且我在currently_locked_for_emailing上坚持了这一事实)
  • 这是正确的方法吗?如何在SQL中执行此操作?

    Disclaimer

    :我来自Rails的背景,过去我曾经有过ORM(活动记录),使所有的链/联接/更容易自动地工作,并且在当前的SQL复杂语句中完全迷失了]]我有一个非常特殊且非常复杂的需求,以防止来自不同服务器(确切地说,它们是……)的大量并发(相同的时间,有时是相同的毫秒)的读取请求(确切地说,它们是......>]
  • < [

    我必须承认,我还没有完全读懂你的问题,因为它很庞大,但是我对你的追求有一个想法。不是将发送部分与SQL部分分开的解决方案吗?因此,创建一个名为queue的新表,并将所有操作插入到新表中。然后,您运行单独的cron /任务,只要在最近X分钟内未联系到特定用户,它就会发送电子邮件。这样,您可以保留独特感。
    mysql sql aws-lambda mysql-5.6
    1个回答
    1
    投票
    © www.soinside.com 2019 - 2024. All rights reserved.