Oli*_* J. 20 jpa locking transactions
我读了甲骨文的博客文章在这里关于JPA和锁定模式.
我并不完全理解OPTIMISTIC和OPTIMISTIC_FORCE_INCREMENT锁模式类型之间的区别.
OPTIMISTIC 模式:

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

当用户选择此模式时,他必须将EntityManager的状态刷新()到数据库中以手动增加版本字段.因此,所有其他乐观交易将失效(回滚).在事务结束时也会检查版本以提交或回滚事务.
看起来很清楚,但什么时候应该使用OPTIMISTIC对比OPTIMISTIC_FORCE_INCREMENT模式?我看到的唯一标准是OPTIMISTIC_FORCE_INCREMENT在我希望事务优先于其他事务时应用模式,因为选择此模式将回滚所有其他正在运行的事务(如果我理解的话,那么很好).
还有其他理由选择此模式而不是OPTIMISTIC模式吗?
谢谢
zbi*_*big 43
不要被这个长长的答案吓到.这个话题并不简单.
默认情况下,如果未指定任何锁定(与使用相同的行为),JPA会强制执行
读取已提交的隔离级别LockModeType.NONE.
读致力于要求不存在的脏读现象.只有T1才能看到T2提交后T2所做的更改.
在JPA中使用乐观锁定会将隔离级别提升到可 重复读取.
如果T1在事务的开始和结束时读取某些数据,则重复读取可确保T1看到相同的数据,即使T2更改了数据并在T1中间提交.
这是棘手的部分.JPA 以最简单的方式实现可重复读取:通过防止 不可重复读取现象.JPA不够复杂,无法保存读取快照.它只是通过上升异常(如果数据从第一次读取更改)来防止第二次读取发生.
您可以从两个乐观锁定选项中进行选择:
LockModeType.OPTIMISTIC(LockModeType.READ在JPA 1.0中)
LockModeType.OPTIMISTIC_FORCE_INCREMENT(LockModeType.WRITE在JPA 1.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
}
Run Code Online (Sandbox Code Playgroud)
现在假设我们在数据库中存储了一个名为John的 Person .我们在T1中读到了这个人,但在第二次交易T2中将他的名字改为迈克.
没有任何锁定
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)
Run Code Online (Sandbox Code Playgroud)
乐观的读锁定
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.
Run Code Online (Sandbox Code Playgroud)
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();
Run Code Online (Sandbox Code Playgroud)
乐观的写锁
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)
Run Code Online (Sandbox Code Playgroud)
尽管JPA规范中有以下注释,但Hibernate和EclipseLink表现良好并且不使用它.
对于版本化对象,允许实现使用LockMode- Type.OPTIMISTIC_FORCE_INCREMENT,其中请求了LockModeType.OPTIMISTIC,但反之亦然.
Jam*_*mes 12
通常,您永远不会使用lock()API进行乐观锁定.JPA将自动检查任何更新或删除的任何版本列.
用于乐观锁定的lock()API的唯一目的是当您的更新依赖于未更改/更新的另一个对象时.如果另一个对象发生更改,这将允许您的事务仍然失败.
何时执行此操作取决于应用程序和用例.OPTIMISTIC将确保在您提交时未更新其他对象.OPTIMISTIC_FORCE_INCREMENT将确保其他对象尚未更新,并将在提交时增加其版本.
乐观锁定始终在提交时得到验证,并且在提交之前无法保证成功.您可以使用flush()提前强制数据库锁定,或触发先前的错误.
| 归档时间: |
|
| 查看次数: |
17338 次 |
| 最近记录: |