如何锁定某些行,因为它们未在其他事务中被选中

时间:2011-01-20 16:19:40

标签: sql mysql concurrency transactions locking

我有一个表格,就像我想要访问的URL列表。该表未被引用,也未引用其他表。 我的申请是做什么的:

  • 从网址列表中选择一些行
  • 开始他们的循环
    • 开始交易
    • 访问网址
    • 详细说明
    • 开始子交易
      • 检查结果是否已在前两个表中(选择)
      • 如果没有,请保存(插入)
    • 提交子事务
    • 开始子交易
      • 检查结果是否已在另一个表中(选择)
      • 如果没有,请保存(插入)
    • 提交子事务
    • 更新我正在访问的行
    • 提交主要交易
  • 结束周期

这里和那里有大量的错误检查,主要事务有数百个查询(选择和插入),mysql在CPU上非常高(我猜是因为大回滚日志),但所有这一切都正常。< / p>

只有我不能运行这个批次的多个实例,因为它选择的行或多或少相同:这意味着我在几秒钟内多次访问一个URL,这是我不想要的。 / p>

如果我将主事务的开始移动到循环之外并选择要更新的行,那么我仍然不会获得多并发,因为第二个实例将不会运行select,直到第一个实例的主事务赢得'提交。

一种可能的解决方案是将第一个表中的“锁定”字段添加到true(实际上是当前日期,因为我尽量不使用布尔值)。

另一种方法是启动主要交易,然后一次只选择一行(用于更新)(设置“限制1”而不是现在的5或10)。

我无法想象获得我想要的其他方式:不要选择锁定的行。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

听起来好像你确实需要某种形式的标记来将行标识为“正在使用”,因此其他实例不会处理相同的数据;无论你使用布尔值还是日期类型是无关紧要的,不知何故你必须标记正在使用的行。

您可以通过调度程序,具有对表的唯一访问权限的进程或线程来执行此操作,并且唯一的工作是选择行并将其传递给其他进程以进行处理。即使这样,调度员也必须知道他们所获得的数据有多远,以便你回到同样的问题。

另一种方法是使用一个字段来表示该行正在使用中(正如您在问题中所述)。每个进程使用唯一ID更新一个行块,在事务内执行以锁定表;我会使用从CONNECTION_ID()返回的连接号来标记它们,然后你知道它是唯一的。

UPDATE ... WHERE connection_id IS NULL(已应用限制)事务完成后,该过程可SELECT ... WHERE connection_id = CONNECTION_ID()获取其行以进行处理。

当他们完成工作后,整个周期再次开始标记下一组行,直到所有行都被处理完毕。