JPA 2.0 - 等待线程的db-lock-release在发布后是否肯定会获取数据?或者万一它仍然符合初始标准?

问题描述 投票:0回答:3

我有一个多线程环境(集群,甚至是多JVM),有很多线程同时查询单个db-table。所有这些线程都在执行完全相同的查询,查找状态为“Available”的任意实体。如果线程找到“可用”实体,它会将其状态更改为“已阻止”并将其分派给执行某些后续工作的业务逻辑。对“可用”实体的此查询是悲观写入锁定查询,因此对于尝试同时访问同一行的任何其他线程,db-table中的相应行被锁定。所有其他线程必须等到前面的线程释放数据库中的锁。

现在我的问题是:在任何情况下释放锁之后,在某个实体上等待锁被释放的线程是否会收到此特定实体?即使实体的状态不再符合初始查询标准?在上面的场景中,如果第二个线程查询状态为“available”的某个实体并找到当前(写入)被第一个线程锁定的实体,是否意味着第二个线程将在任何实体发布之后获取该实体即使第一个线程在释放锁定之前同时将其状态更改为“已阻止”?

java-ee jpa db2 jpa-2.0 openjpa
3个回答
0
投票

悲观锁定:

在您的方案中,查询1获取具有“可用”状态的行,然后将状态更新为“已阻止”。如果它没有提交(或回滚)此更新,那么当搜索“可用”行的其他查询尝试读取此行时,它们将等待 - 它们在锁定时无法读取该行的值。

如果查询1提交更新(即状态现在是“已阻止”),则其他查询将不会获得该行。

如果查询1执行回滚(行的状态恢复为“可用”),则其他查询将获得其结果集中的行。

要在这种情况下实现最佳并发性,请确保事务执行此更新尽可能短(即将执行后续工作的业务逻辑分离到单独的事务中)。当业务逻辑完成时,然后对其成功/失败做出决定,然后再次更新有问题的行。


0
投票

问题是特定于数据库,并且恕我直言与JPA无关。答案是:Thread2将接收该特定实体(其锁定首先由Thread1保持),如果它仍然符合您的搜索条件(否则:这是什么类型的数据库?:您要求苹果,它返回橙色)。

现在,如果您想自己测试它,请打开两个控制台会话到您的数据库并自己尝试。

PS:在等待释放锁时也考虑超时。


0
投票

“这是否意味着第二个线程在任何情况下都会在释放后获得该实体,即使第一个线程在释放锁定之前同时改变其状态(...)?”

我会说它高度依赖于持久性提供程序和底层数据库,因为JPA规范说明要实现什么而不是如何实现。

如JPA 2.0规范,3.4.3章悲观锁定中所述:

此规范未定义持久性提供程序用于获取数据库锁的机制,而可移植应用程序不应依赖于如何在数据库上实现悲观锁定。例如,如果该构造提供了适当的语义,则持久性提供程序可以使用底层数据库平台的SELECT FOR UPDATE语句来实现悲观锁定,或者提供程序可以使用可重复读取的隔离级别。

另一方面,使用LockModeType.PESSIMISTIC_WRITE保证可重复读取isolation level,防止不可重复读取和脏读取异常,因此如果底层数据库并发控制机制提供可比较的语义(即两阶段锁定或多版本并发控制),这就足够了特殊情况,因为OpenJPA提供了悲观写锁定,DB2提供了满足条件的RS或RR隔离级别。

© www.soinside.com 2019 - 2024. All rights reserved.