我有一个表格,类似于我想要访问的 URL 列表。该表未被引用,也未引用其他表。 我的应用程序的作用是:
- 从 URL 列表中选择一些行
- 开始一个循环
- 开始交易
- 访问网址
- 详细说明
- 开始子交易
- 检查结果是否已在前两个表中(选择)
- 如果没有,请保存(插入)
- 提交子事务
- 开始子交易
- 检查结果是否已在另一个表中(选择)
- 如果没有,请保存(插入)
- 提交子事务
- 更新我正在访问的行
- 提交主事务
- 结束循环
到处都有大量的错误检查,主事务有数百个查询(选择和插入),mysql 的 CPU 占用率非常高(我猜是因为回滚日志很大),但所有这些都工作正常。
只是我无法运行该批处理的多个实例,因为它选择的行或多或少相同:这意味着我在几秒钟内多次访问某个 URL,这是我不希望的。
如果我将主事务的开始移到循环之外并选择要更新的行,我仍然不会获得多重并发,因为第二个实例不会运行选择,直到第一个实例的主事务不会运行提交。
一个可能的解决方案是在第一个表中添加一个“锁定”字段以设置为 true(实际上是当前日期,因为我尝试不使用 bool 值)。
另一种方法是启动主事务,然后一次仅选择一行(用于更新)(设置“限制 1”而不是现在的 5 或 10)。
我无法想象其他方式来获得我想要的东西:不要选择锁定的行。
有什么想法吗?
最佳答案
听起来好像您确实需要某种形式的标记来将行标识为“正在使用”,以便其他实例不会处理相同的数据;无论您使用 bool 类型还是日期类型都无关紧要,您必须以某种方式标记正在使用的行。
您可以通过调度程序、只能访问您的表的进程或线程来执行此操作,其唯一的工作是选择行并将它们传递给其他进程进行处理。即使这样,调度员也必须知道他们已经获取了多少数据,这样你就会回到同样的问题。
另一种方法是使用字段来指示该行正在使用中(正如您在问题中所说)。每个进程都会更新具有唯一 ID 的行 block ,在事务内执行以锁定表;我会使用从 CONNECTION_ID()
返回的连接号来标记它们,然后你就知道它是唯一的。
在UPDATE ... WHERE connection_id IS NULL
(应用了限制)事务完成后,该过程可以SELECT ... WHERE connection_id = CONNECTION_ID()
来获取他们的行进行处理。
当他们完成工作时,整个循环再次开始标记下一组行,直到所有行都已处理完毕。
关于sql - 如何锁定某些行,因为它们在其他事务中没有被选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4749636/