mysql 如何在不锁定的情况下从多线程应用程序访问表行?

zd287kbt  于 2023-04-29  发布在  Mysql
关注(0)|答案(1)|浏览(158)

我正在开发一个应用程序,其中包含了一些数据。现在,我想根据列“RefreshMe”刷新该表中的一些行。
例如:

CREATE TABLE IF NOT EXISTS `datatable` (
  `id` bigint(20) NOT NULL,
  `row_created` datetime(6) NOT NULL,
  `row_modified` datetime(6) DEFAULT NULL,
  `refresh_me` bit(1) DEFAULT NULL,
  `refresh_date` datetime(6) DEFAULT NULL,
  `next_refresh_date` datetime(6) DEFAULT NULL,
  `refresh_days` int(11) NOT NULL,
  `version` bigint(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

如果RefreshMe为true,则应刷新该行。
问题是:如何从多线程应用程序中选择该表中的行,同时尽量减少冲突?
我不想使用select for update来完成这个任务。只需使用乐观锁(springjpa)。
如果我只使用select * from datatable where refresh_me = 1 order by row_modified asc;,那么线程将获得相同的行,并且应该解析乐观锁。
我能想到的唯一方法是选择100行,随机选取10行并使用它们。这将减少2-10个正在运行的线程之间的冲突。
如何解决100个线程的任务?”””有更好的方法来做到这一点?**

qyyhg6bp

qyyhg6bp1#

“多线程”是指刷新行的大量进程?
如果是这样的话,我建议你使用预先预订。
refresh_me更改为BIGINT UNSIGNED NULL。
接受以下值:

  • NULL -不需要刷新,
  • 0 -需要刷新,不保留,
  • 其他值-线程连接的CONNECTION_ID(),它保留此行以供刷新。

当必须刷新行时,则将其refresh_me设置为0。
必须刷新行的线程保留所需的行数,以便用

UPDATE datatable
SET refresh_me = CONNECTION_ID()
WHERE refresh_me = 0
-- ORDER BY ...
LIMIT NNN;

如果受影响的行的数量为零,则不存在需要刷新的行,并且线程可以退出或休眠。
然后,它使用以下命令逐个处理保留行(由于并发线程干扰,它们的数量可能小于指定的NNN值):

-- get one reserved row
SELECT *
FROM datatable
WHERE refresh_me = CONNECTION_ID()
LIMIT 1;

-- process selected row identified by its PK value using SQL and/or application code
...

-- save new data state
UPDATE datatable
SET ...
WHERE primary_key_column = ...;

迭代保留行,直到下一次迭代不返回保留行(即,即所有保留行都已被处理)。在这种情况下,下一行块被保留。
使用这种预保留,保留大量行是没有意义的。您只能保留一行(i)。即使用LIMIT 1),然后处理它,或者如果行被并发线程重新保留(在UPDATE LIMIT 1之后进一步SELECT不返回行),重复保留该行的尝试。
线程可能挂起/失败。因此,我建议您添加自动使用的updated_at列,并创建一个事件过程,该过程检查保留但从保留时间点经过的时间太高的行,并将这些行返回到需要用简单刷新的行池。

UPDATE datatable 
SET refresh_me = 0 
WHERE refresh_me 
  AND updated_at < CURRENT_TIMESTAMP - INTERVAL NNN SECOND;

相关问题