Java 如何在应用层正确地实现乐观锁定?

Java 如何在应用层正确地实现乐观锁定?,java,mysql,Java,Mysql,我有点困惑,为什么乐观锁定实际上是安全的。如果我检查检索时的版本和更新时的版本,那么如果操作系统发出中断并在提交实际发生之前交换进程,我仍然可以有两个请求进入更新块。例如: latestVersion = vehicle.getVersion(); if (vehicle.getVersion() == latestVersion) { // update record in database } else { // don't update record } 在本例中,我尝

我有点困惑,为什么乐观锁定实际上是安全的。如果我检查检索时的版本和更新时的版本,那么如果操作系统发出中断并在提交实际发生之前交换进程,我仍然可以有两个请求进入更新块。例如:

latestVersion = vehicle.getVersion();
if (vehicle.getVersion() == latestVersion) {
    // update record in database
} else {
    // don't update record 
}

在本例中,我尝试在Java应用程序中手动使用乐观锁定,而不使用JPA/Hibernate。但是,似乎两个请求可以同时进入
if
块。你能帮我理解如何正确地做这件事吗?就上下文而言,我还以网站为例。

嗯。。。这是乐观的部分。乐观的是它是安全的。如果你必须确定它是安全的,那就不乐观了

您展示的示例肯定会受到竞争条件的影响。这不仅是因为线程调度,还因为事务隔离级别

MySQL中的简单读取(默认事务隔离级别为REPEATABLE read)将读取事务启动时提交的数据

然而,更新数据将作用于更新时提交的数据。如果其他并发会话同时更新了数据库中的行并提交了它,那么更新将“看到”最新提交的行,而不是get方法查看的行

避免竞争状况的方法是不要乐观。相反,强制以独占方式访问该记录

如果您只有一个应用程序实例,您可能会为此使用关键部分


如果您有多个应用程序实例,则关键部分无法协调其他实例,因此您需要在数据库中进行协调。可以通过使用悲观锁定来实现这一点。您可以使用a阅读记录,也可以使用。

非常感谢您提供的详细答案。在检索时阅读版本,然后在更新时将版本号添加到WHERE子句,您的想法是什么?例如,下面的伪代码
更新表,其中version=latestVersion
是乐观的。:-)如果更新报告它影响了零行,您希望代码做什么?也就是说,自从get方法最初读取它以来,版本必须已更改。我想我真的不明白乐观锁定的意义。这似乎只是为版本检查增加了一笔“无用”的费用,即使它不能防止出现冲突的更新。这不适用于您的使用模式,但当您不需要将数据的客户端副本与数据库中的相应数据保持同步时,它很有用。这就是ORM使用模式的谬误。他们试图假装客户端对象就像数据库中数据的门面,但事实并非如此。