我有一个非常特殊且非常复杂的需求,以防止来自来自不同服务器的大量并发(同一秒,有时是相同的毫秒)请求的读取](准确地说,它们是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_id
和customer_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举例来说:
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
的语句>customer_id= 7
和hobby_idea_article_id= 12
的语句...等等...唯一的“业务逻辑”保证是我永远不会有两个具有相同输入对(customer_id= 8
,hobby_id
)的并发lambda”。
因此,当前的SO问题是关于[[如何确保客户在处理来自大量并发lambda的请求时,永远不会向同一收件人发送两封快速电子邮件(一封在另一封之后几秒钟) ?问题的说明是:
customer_id
和hobby_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负责处理传递有数据的电子邮件)]]
以相同的秒数/毫秒执行的并行lambda
执行[email protected]
和hobby_idea_article_id= 4
的SQL语句(实际上,我可以有8个客户想要关于嗜好的想法“以id = 4进行钓鱼!)。此lambda 检索大致相同的数据customer_id= 7
输入仅用于过滤出已经获得作者的作者举例来说,假设由于客户12天前已经用customer_id
7通知了john
,所以它过滤掉了john
,所以这里检索到的数据是:] >customer_id=
这意味着我将在几秒钟后向[email protected]发送电子邮件(由传递了此数据的另一个lambda执行)这里是问题:[email protected]将收到2封快速电子邮件
,但我绝对不想允许这种事情。我在当前SQL语句中拥有的保护(请参阅条件1和2hobby_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]
使用行锁吗?
阅读后,我考虑过要在
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.6我读了很多其他文章(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想要确定这一点。
true
,要使行锁起作用,必须绝对有一个索引...一个人甚至说here”“我自己的测试表明,使用在未索引列上的过滤器将导致整个表的锁定,而在已索引列上的过滤器将导致过滤的行锁定的预期行为。”是真的,那我应该说什么呢,这不像我的where是在1或2列上简单的...在我的所有where子句列上的索引都会很复杂吗?]]2。解决方案2-对select ... update进行补充,因为即使我正确地获得了1.,我仍然有一个重要的问题:
如果我正确理解“行锁”会锁定SELECT结果中的所有行,那么这里就是问题所在。但是我需要的真正的锁定不仅是针对选择结果的行,而且我需要将行锁定设置为作者具有与SELECT结果内的行相同值的任何行] >
[让我通过一个示例解释为什么我使用与1相同的数据。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执行)
[email protected]
而不会选择它们(请参见新的SQL语句WHERE子句'currently_locked_for_emailing'= true
,...但是我还有一个大问题。
hobby_id = 9
currently_locked_for_emailing = 'false'
正如您所看到的,因为这里有一个特殊的情况,行锁定的策略不起作用:确实,因为作者是相同的([ C0]),但是它没有被第一个SQL语句锁定,也没有分配我希望第二个lambda不能获取此数据
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
更新)::>hobby_idea_article_id= 4
的任何其他行,该行与SELECT的结果行之一具有相似的“作者”值在第1行和第2行上,我都将应用事务处理策略,并将currently_locked_for_emailing = true
设置为Hobby_ideas_articles
(直到发送了实际的电子邮件,并且我在currently_locked_for_emailing
上坚持了这一事实)Disclaimer
:我来自Rails的背景,过去我曾经有过ORM(活动记录),使所有的链/联接/更容易自动地工作,并且在当前的SQL复杂语句中完全迷失了]]我有一个非常特殊且非常复杂的需求,以防止来自不同服务器(确切地说,它们是……)的大量并发(相同的时间,有时是相同的毫秒)的读取请求(确切地说,它们是......>]