@Entity public class Employee { @Id private String id; @Version private Integer version; }Transaction T1:
EntityTransaction transaction1 = em1.getTransaction(); transaction1.begin(); Employee employeeT1 = em1.find(Employee.class, "123001", LockModeType.OPTIMISTIC, null); employeeT1.setName("New Name1");Transaction T2:
EntityTransaction transaction2 = em2.getTransaction(); transaction2.begin(); Employee employeeT2 = em2.find(Employee.class, "123001", LockModeType.OPTIMISTIC, null); employeeT2.setName("New Name2");Commit transaction T1:
transaction1.commit();T1 is successfully committed and the version of the entity is increased by 1.
Now commit transaction T2:
transaction2.commit();OptimisticLockException is thrown, and T2 is marked for rollback only since the version of the entity was changed by T1.
Lock mode: OPTIMISTIC_FORCE_INCREMENT is the same as OPTIMISTIC except the version of an entity will be increased even if the entity is not changed.
Transaction T1:
EntityTransaction transaction1 = em1.getTransaction(); transaction1.begin(); Employee employeeT1 = em1.find(Employee.class, "123001", LockModeType.PESSIMISTIC_WRITE, null);Transaction T2:
EntityTransaction transaction2 = em2.getTransaction(); transaction2.begin(); em2.find(Employee.class, "123001", LockModeType.PESSIMISTIC_READ, null);Transaction T2 will not be able to obtain the read lock on the entity since it is exclusively locked by Transaction T1, and LockTimeoutException or PessimisticLockException will be thrown. If a PessimisticLockException is thrown, the transaction will be marked for rollback only.
Transaction T1 will be successfully committed.
transaction1.commit();
Lock timeout and scope are hints, and they can be passed to any method that takes a lock mode parameter, or annotation/XML mapping that contains a lock-mode element. For example,
EntityManager
Map<String, Object> properties = new HashMap<>(); properties.put("javax.persistence.lock.timeout", 2000) properties.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED); em.find(Employee.class, "123001", LockModeType.PESSIMISTIC_WRITE, properties);Query or TypedQuery:
TypedQuery<Employee> query = em.createQuery("select e from Employee e where id='123001'", Employee.class); query.setLockMode(LockModeType.PESSIMISTIC_WRITE); query.setHint("javax.persistence.lock.timeout", 2000); query.setHint("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED);Named query:
<named-query name="jpqlListFullTimeEmployeesBySalary"> <query>select e from FullTimeEmployee e where e.salary between ?1 and ?2 order by e.salary desc, e.name asc</query> <lock-mode>PESSIMISTIC_WRITE</lock-mode> <hint name="javax.persistence.lock.timeout" value="2000"></hint> <hint name="javax.persistence.lock.scope" value="EXTENDED"></hint> </named-query>Create EntityManagerFactory:
Map<String, Object> properties = new HashMap<>(); properties.put("javax.persistence.lock.timeout", 2000) properties.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED); Persistence.createEntityManagerFactory("pu-name", properties);META-INF/persistence.xml
<persistence> <persistence-unit name="pu-name"> <properties> <property name="javax.persistence.lock.timeout" value="2000"/> <property name="javax.persistence.lock.scope" value="EXTENDED"/> <properties> <persistence-unit> </persistence>