从非托管连接更改数据时的 JPA @Version 行为

JPA @Version behavior when data is changed from unmanaged connection

在 table Customer 上启用 @Version 当 运行 进行以下测试时

@Test
public void actionsTest1 () throws InterruptedException {
    CustomerState t = customerStateRepository.findById(1L).get();
    Thread.sleep(20000);
    t.setInvoiceNumber("1");
    customerStateRepository.save(t);
}

actionsTest1 正在睡觉时,我 运行 actionsTest2 将发票编号更新为 2。

@Test
public void actionsTest2 () throws InterruptedException {
    CustomerState t = customerStateRepository.findById(1L).get();
    t.setInvoiceNumber("2");
    customerStateRepository.save(t);
}

当 actionsTest1 returns 休眠时,它也尝试更新,并获得 ObjectOptimisticLockingFailureException

按预期工作。

但是如果我 运行 actionsTest1 并且在它处于休眠状态时我打开一个 SQL 终端并进行

的原始更新
update customer 
set invoice_number='3' where id=1

actionsTest1 returns 休眠时,它的版本控制机制没有捕捉到这种情况并将值更新回 1。

这是预期的行为吗?版本控制是否仅适用于 JPA 管理的连接?

Is that expected behavior?

是的。

Does versioning work only with connections managed by JPA?

不,它在使用任何其他方式更新数据时也有效。但是所有更新数据的东西都必须遵守乐观锁的规则:

  1. 每当执行任何更新时增加版本列
  2. (仅当其他进程也想检测并发更新时才需要):在每次更新时检查版本号自加载更新所基于的数据以来没有变化。

它按预期工作。如果您手动更新,您也必须更新您的版本。

如果您将 JPA 与 @Version 一起使用,JPA 会递增版本列。

要获得预期结果,您必须像这样编写语句

update customer set invoice_number='3', version=XYZ (mabye version+1) where id=1

自动休眠 increases/changes 数据库中 @Version 映射列中的值。

当您获取实体记录时,hibernate 会保留数据记录的副本以及 @Version 的值。在执行 mergeupdate 操作时,hibernate 检查 Version 中的当前值是否仍然相同,并与之前获取的实体副本匹配。 如果该值匹配,则意味着该实体不是脏的(未被任何其他事务更新)否则将抛出异常。