mysql - MySQL 分页检索数据,避免竞争条件
问题描述
我的服务是集群的,我正在运行它的几个实例。我需要以分页方式收集所有实体并将它们推送到缓存层(Redis)。在一台应用程序服务器上执行此操作时,在服务器 #2 上运行的应用程序可能已经在进行更改。
那些对 db 的分页调用将在一次调用中获取 1000 个项目。现在,由于我想在检索过程中防止修改,我该如何实现呢?
SELECT FOR UPDATE
即使我没有更新此事务中的任何内容,但仅以分页方式获取数据,我是否可以使用机制?
解决方案
如果它是一个具有多个线程的应用程序实例,则可以使用临界区。但这不适用于应用程序实例集群。
几个月前,我为一项服务实现了这一点。该应用程序部署在多个实例中。这些实例不相互通信,因此它们不能直接协调。但它们都连接到同一个 MySQL 数据库。
我所做的是使用 MySQL 的GET_LOCK()内置函数。
当例程想要独占访问时,它会调用GET_LOCK('mylock', 0)
. 这会立即返回,如果它获得了锁,则返回一个真值,如果该锁已被其他某个客户端持有,则返回一个假值。这告诉客户端应用程序它是否是“赢家”。
如果客户不是赢家,那么它会打电话GET_LOCK('mylock', -1)
,这意味着无限期地等待。这样做是因为获胜者正在处理关键部分需要做的任何事情。
当获胜者结束时,它必须跟注RELEASE_LOCK('mylock')
。这会解除对等待的客户的阻止。他们现在知道临界区的工作已经完成,他们可以随意读取缓存的内容或他们需要做的任何其他事情。
还要记住,正在等待的客户端GET_LOCK('mylock', -1)
需要RELEASE_LOCK('mylock')
立即调用,因为一旦他们停止等待,他们实际上是自己获得了锁。
这种设计允许多个客户端使用单个锁协调器 (MySQL)。它实现了悲观锁定,无需依赖锁定任何表或行集。
推荐阅读
- aws-lambda - 在 lambda 函数中解析私有主机名
- oracle - 我想将光标从一个过程传递到另一个过程
- mysql - 如何在 SQLite 中使用 compareTo() 的功能?
- ruby-on-rails-5 - Rails 5嵌套参数允许false
- r - 从 RStudio 中的 mclapply() 调用时,ggsave() 不起作用;有解决方法吗?
- python - 在 Python 中匹配来自多个 txt 文件的值
- amazon-web-services - 使用无服务器,如何将 Lambda 函数的授权方设置为资源中的 Cognito 用户池?
- python - 如何在 Tkinter 中高效地创建大量条目?
- c - 我在 C 中用于两组 UNION 的代码不起作用
- node.js - pm2 操作不允许