【问题标题】:SQL - to lock or not to lock: selecting next unused codeSQL - 锁定或不锁定:选择下一个未使用的代码
【发布时间】:2016-03-24 02:47:22
【问题描述】:

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

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

使用 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 次)试用后 - 抛出异常。

任何帮助/建议将不胜感激。 提前谢谢你

【问题讨论】:

  • 好的,删除 sql-server....

标签: java mysql sql database


【解决方案1】:

第二种选择 - 乐观锁定 - 似乎是一个非常糟糕的主意。
来自维基百科: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 .....
    .....
    .....
    等等等等。很多冲突和重试。

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

【讨论】:

  • 谢谢!我们实施了第一个选项,但最好有人确认。
猜你喜欢
  • 2018-02-10
  • 1970-01-01
  • 2018-11-09
  • 2012-12-16
  • 1970-01-01
  • 2021-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多