SQL - 锁定或不锁定:选择下一个未使用的代码

时间:2016-03-19 14:06:39

标签: java mysql sql database

请对以下问题提供一些建议: 我有一个唯一代码列表。代码必须只使用一次,因此每个代码都有一个状态(使用/未使用)。

如果多个线程试图获取下一个未使用的代码,我担心争用/竞争条件。

使用SQL数据库(在我的情况下是MySQL)实现它的最佳方法是什么?

第一个选项是使用锁定和读取提交的隔离级别:

start transaction in read-committed isolation level
select code from code_table where status = 'not-used' for update
update code_table set status = 'used' where code = :code
commit transaction

在争用线程的情况下,我认为“数据库线程”会在锁定的行上偶然发现,除非行写入锁定将被释放,否则将会看到(因为读取已提交的隔离级别)代码记录已被使用并转移到其他代码记录。

第二个选项是使用类似于hibernate乐观锁定的东西(我们不使用hibernate),这里是步骤的描述:

start transaction in default isolation level ( read-repeatable )
select code from code_table where status = 'not-used'
commit transaction

start transaction in default isolation level ( read-repeatable )
update code_table set status = 'used' where code = :code
commit transaction

在Java代码中,我将检查更新了多少记录。如果有一条记录更新,一切正常,如果有0条记录更新 - 我重复步骤...在第3(或第5)试验后 - 抛出异常。

任何帮助/建议都将受到高度赞赏。 提前谢谢

1 个答案:

答案 0 :(得分:2)

第二种选择 - 乐观锁定 - 似乎是一个非常糟糕的主意 来自WIkipedia:https://en.wikipedia.org/wiki/Optimistic_concurrency_control

  

乐观并发控制(OCC)。 。 。 。 。 。 。
  。 。 。 。 。 。 。 。通常用于   数据争用率低的环境。当冲突很少时,   事务可以完成,而无需管理锁和   没有交易等待其他交易'锁定   清除,导致比其他并发控制更高的吞吐量   方法。但是,如果频繁争用数据资源,那么   反复重启事务的成本会损害性能   显著;人们普遍认为其他并发控制   方法在这些条件下具有更好的性能。然而,   基于锁定("悲观")方法也可以提供差   性能,因为锁定可以大大限制有效   即使在避免死锁的情况下也能实现并发。

我可以很容易地想象出X并发线程的以下场景:

  • 主题#1获取下一个未使用的记录#1
  • 线程#2获取下一个未使用的记录#1
  • 线程#3获取下一个未使用的记录#1
  • 主题#4获取下一个未使用的记录#1
    .....
    .....
  • 主题#1更新记录#1,然后获取下一个可用记录#2
  • 线程#2 在尝试更新记录#1时检测到冲突,因此重试并获取下一个可用记录#2
  • 线程#3 在尝试更新记录#1时检测到冲突,因此重试并获取下一个可用记录#2
  • 线程#4 检测到冲突,同时尝试更新记录#1,因此重试并获取下一个可用记录#2 .....
    .....
    .....
    等等等等。很多冲突和重试。

你必须坚持第一个选择。
为了减少争用,您可能希望将事务保持尽可能短。