我在Oracle的博客上读到了一篇关于JPA和锁定模式的文章。
我不完全理解OPTIMISTIC和OPTIMISTIC_FORCE_INCREMENT锁模式类型之间的区别。
OPTIMISTIC 模式:

当用户使用此模式锁定实体时,将在事务开始时对版本字段实体(@version)进行检查,并在事务结束时对版本字段进行检查。如果版本不同,则事务回滚。
OPTIMISTIC_FORCE_INCREMENT 模式:

当用户选择这种模式时,他必须将EntityManager的状态刷新到数据库中,以手动增加version字段。因此,所有其他乐观事务都将失效(回滚)。在事务结束时还会对版本进行检查,以提交或回滚事务。
这似乎很明显,但我应该在什么时候使用OPTIMISTIC和OPTIMISTIC_FORCE_INCREMENT模式?我看到的唯一条件是,当我希望事务优先于其他事务时,应用OPTIMISTIC_FORCE_INCREMENT模式,因为选择此模式将回滚所有其他正在运行的事务(如果我完全理解机制的话)。
选择此模式而不是OPTIMISTIC模式还有其他原因吗?
谢谢
发布于 2012-11-27 15:09:06
通常,您永远不会使用lock() API来进行乐观锁定。JPA将自动检查任何更新或删除的任何版本列。
用于乐观锁定的lock() API的唯一用途是,当您的更新依赖于另一个未更改/更新的对象时。这允许您的事务在其他对象更改时仍然失败。
什么时候这样做取决于应用程序和用例。乐观将确保在提交时未更新其他对象。OPTIMISTIC_FORCE_INCREMENT将确保其他对象未被更新,并将在提交时增加其版本。
乐观锁定总是在提交时得到验证,并且在提交之前无法保证成功。您可以使用flush()提前强制数据库锁,或者触发更早的错误。
发布于 2014-08-26 13:48:40
别被这么长的回答吓到了。这个话题并不简单。
默认情况下,如果不指定任何锁定(与使用LockModeType.NONE相同的行为),JPA将强制执行读提交隔离级别。
读提交要求不存在的脏读现象。简单地说,T1只能看到T2在提交T2之后所做的更改。
在JPA中使用乐观锁定可以将隔离级别提高到Repetable reads。
如果T1在事务开始和结束时读取一些数据,Repetable读取将确保T1看到相同的数据,即使T2更改了数据并在T1中间提交。
接下来是棘手的部分。JPA以最简单的方式实现可重复读取:通过防止不可重读现象。JPA不够复杂,无法保存读取的快照。它只是通过上升异常来防止第二次读取(如果数据已经从第一次读取更改)。
您可以从两个乐观锁定选项中进行选择:
LockModeType.OPTIMISTIC (LockModeType.READ in JPA1.0)LockModeType.OPTIMISTIC_FORCE_INCREMENT (LockModeType.WRITE in JPA1.0)这两者有什么区别?
让我举例说明一下这个Person实体。
@Entity
public class Person {
@Id int id;
@Version int version;
String name;
String label;
@OneToMany(mappedBy = "person", fetch = FetchType.EAGER)
List<Car> cars;
// getters & setters
}现在假设我们在数据库中存储了一个名为John的人。我们在T1中读到了这个人,但在第二个事务T2中将他的名字改为Mike。
没有任何锁定的
Person person1 = em1.find(Person.class, id, LockModeType.NONE); //T1 reads Person("John")
Person person2 = em2.find(Person.class, id); //T2 reads Person("John")
person2.setName("Mike"); //Changing name to "Mike" within T2
em2.getTransaction().commit(); // T2 commits
System.out.println(em1.find(Person.class, id).getName()); // prints "John" - entity is already in Persistence cache
System.out.println(
em1.createQuery("SELECT count(p) From Person p where p.name='John'")
.getSingleResult()); // prints 0 - ups! don't know about any John (Non-repetable read)乐观读锁
Person person1 = em1.find(Person.class, id, LockModeType.OPTIMISTIC); //T1 reads Person("John")
Person person2 = em2.find(Person.class, id); //T2 reads Person("John")
person2.setName("Mike"); //Changing name to "Mike" within T2
em2.getTransaction().commit(); // T2 commits
System.out.println(
em1.createQuery("SELECT count(p) From Person p where p.name='John'")
.getSingleResult()); // OptimisticLockException - The object [Person@2ac6f054] cannot be updated because it has changed or been deleted since it was last read.
当对其他实体(可能是非拥有的关系)进行更改时使用LockModeType.OPTIMISTIC_FORCE_INCREMENT,并且我们希望保持完整性。让我举例说明约翰买了一辆新车。
乐观读锁
Person john1 = em1.find(Person.class, id); //T1 reads Person("John")
Person john2 = em2.find(Person.class, id, LockModeType.OPTIMISTIC); //T2 reads Person("John")
//John gets a mercedes
Car mercedes = new Car();
mercedes.setPerson(john2);
em2.persist(mercedes);
john2.getCars().add(mercedes);
em2.getTransaction().commit(); // T2 commits
//T1 doesn't know about John's new car. john1 in stale state. We'll end up with wrong info about John.
if (john1.getCars().size() > 0) {
john1.setLabel("John has a car");
} else {
john1.setLabel("John doesn't have a car");
}
em1.flush();乐观写锁
Person john1 = em1.find(Person.class, id); //T1 reads Person("John")
Person john2 = em2.find(Person.class, id, LockModeType.OPTIMISTIC_FORCE_INCREMENT); //T2 reads Person("John")
//John gets a mercedes
Car mercedes = new Car();
mercedes.setPerson(john2);
em2.persist(mercedes);
john2.getCars().add(mercedes);
em2.getTransaction().commit(); // T2 commits
//T1 doesn't know about John's new car. john1 in stale state. That's ok though because proper locking won't let us save wrong information about John.
if (john1.getCars().size() > 0) {
john1.setLabel("John has a car");
} else {
john1.setLabel("John doesn't have a car");
}
em1.flush(); // OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)尽管JPA规范中有一个注释,Hibernate和EclipseLink表现得很好,而且不使用它。
对于版本对象,允许实现在请求LockModeType.OPTIMISTIC的情况下使用LockMode- LockModeType.OPTIMISTIC,反之亦然。
发布于 2016-12-16 13:54:13
LockModeType.OPTIMISTIC存在check-then-act问题,所以最好将它与PESSIMISTIC_READ或PESSIMISTIC_WRITE耦合起来。
另一方面,LockModeType.OPTIMISTIC_FORCE_INCREMENT不存在任何数据不一致问题,您通常会在修改子实体时使用它来控制父实体的版本。
例如,您可以使用LockModeType.OPTIMISTIC_FORCE_INCREMENT或LockModeType.PESSIMISTIC_FORCE_INCREMENT,以便使考虑到子实体更改的父实体版本故事。
https://stackoverflow.com/questions/13581603
复制相似问题