java - SQL - 锁定或不锁定 : selecting next unused code

标签 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 次)试验后——抛出异常。

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

最佳答案

第二种选择——乐观锁定——似乎是个很糟糕的主意。
来自维基百科:https://en.wikipedia.org/wiki/Optimistic_concurrency_control

Optimistic concurrency control (OCC) . . . . . . .
. . . . . . . . is generally used in environments with low data contention. When conflicts are rare, transactions can complete without the expense of managing locks and without having transactions wait for other transactions' locks to clear, leading to higher throughput than other concurrency control methods. However, if contention for data resources is frequent, the cost of repeatedly restarting transactions hurts performance significantly; it is commonly thought that other concurrency control methods have better performance under these conditions. However, locking-based ("pessimistic") methods also can deliver poor performance because locking can drastically limit effective concurrency even when deadlocks are avoided.

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

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

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

关于java - SQL - 锁定或不锁定 : selecting next unused code,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36102729/

相关文章:

Java 文本文件从四列文本文件中删除 double

mysql - MySQL 中的 6 位数字列

MySQL:为具有多个 BETWEEN 表达式的 WHERE 子句建立索引

SQL Server 显示不同列数大于 1 的结果

SQL 条件行插入

java - 带有 mongodb PostAuthorize 和 PreAuthorize 的 Spring Boot 安全性不起作用

javax.transaction.Transactional 与 org.springframework.transaction.annotation.Transactional

java - 在jframe上动态切换图像

php - 如果使用 group by 进行 mysql SUM 查询时没有记录,则将其设为 0 而不是 null

mysql - 使用 CONVERT_TZ 会导致性能问题吗?