diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java b/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java
index 130edec8cc..e8fdabebbc 100644
--- a/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java
+++ b/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java
@@ -1,30 +1,12 @@
package com.baeldung.hibernate;
-import com.baeldung.hibernate.pojo.Employee;
-import com.baeldung.hibernate.pojo.EntityDescription;
-import com.baeldung.hibernate.pojo.OrderEntry;
-import com.baeldung.hibernate.pojo.OrderEntryIdClass;
-import com.baeldung.hibernate.pojo.OrderEntryPK;
-import com.baeldung.hibernate.pojo.PointEntity;
-import com.baeldung.hibernate.pojo.PolygonEntity;
-import com.baeldung.hibernate.pojo.Product;
-import com.baeldung.hibernate.pojo.Phone;
-import com.baeldung.hibernate.pojo.TemporalValues;
-import com.baeldung.hibernate.pojo.Course;
-import com.baeldung.hibernate.pojo.Student;
-import com.baeldung.hibernate.pojo.User;
-import com.baeldung.hibernate.pojo.UserProfile;
-import com.baeldung.hibernate.pojo.inheritance.Animal;
-import com.baeldung.hibernate.pojo.inheritance.Bag;
-import com.baeldung.hibernate.pojo.inheritance.Book;
-import com.baeldung.hibernate.pojo.inheritance.Car;
-import com.baeldung.hibernate.pojo.inheritance.MyEmployee;
-import com.baeldung.hibernate.pojo.inheritance.MyProduct;
-import com.baeldung.hibernate.pojo.inheritance.Pen;
-import com.baeldung.hibernate.pojo.inheritance.Person;
-import com.baeldung.hibernate.pojo.inheritance.Pet;
-import com.baeldung.hibernate.pojo.inheritance.Vehicle;
-
+import com.baeldung.hibernate.pessimisticlocking.Individual;
+import com.baeldung.hibernate.pessimisticlocking.PessimisticLockingCourse;
+import com.baeldung.hibernate.pessimisticlocking.PessimisticLockingEmployee;
+import com.baeldung.hibernate.pessimisticlocking.PessimisticLockingStudent;
+import com.baeldung.hibernate.pojo.*;
+import com.baeldung.hibernate.pojo.Person;
+import com.baeldung.hibernate.pojo.inheritance.*;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
@@ -82,6 +64,12 @@ public class HibernateUtil {
metadataSources.addAnnotatedClass(PointEntity.class);
metadataSources.addAnnotatedClass(PolygonEntity.class);
metadataSources.addAnnotatedClass(com.baeldung.hibernate.pojo.Person.class);
+ metadataSources.addAnnotatedClass(Individual.class);
+ metadataSources.addAnnotatedClass(PessimisticLockingEmployee.class);
+ metadataSources.addAnnotatedClass(PessimisticLockingStudent.class);
+ metadataSources.addAnnotatedClass(PessimisticLockingCourse.class);
+ metadataSources.addAnnotatedClass(com.baeldung.hibernate.pessimisticlocking.Customer.class);
+ metadataSources.addAnnotatedClass(com.baeldung.hibernate.pessimisticlocking.Address.class);
Metadata metadata = metadataSources.buildMetadata();
return metadata.getSessionFactoryBuilder()
diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/Address.java b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/Address.java
new file mode 100644
index 0000000000..c889cb6127
--- /dev/null
+++ b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/Address.java
@@ -0,0 +1,34 @@
+package com.baeldung.hibernate.pessimisticlocking;
+
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class Address {
+
+ private String country;
+ private String city;
+
+ public Address(String country, String city) {
+ this.country = country;
+ this.city = city;
+ }
+
+ public Address() {
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+}
diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/Customer.java b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/Customer.java
new file mode 100644
index 0000000000..cb73cbc958
--- /dev/null
+++ b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/Customer.java
@@ -0,0 +1,58 @@
+package com.baeldung.hibernate.pessimisticlocking;
+
+import javax.persistence.*;
+import java.util.List;
+
+@Entity
+public class Customer {
+
+ @Id
+ private Long customerId;
+ private String name;
+ private String lastName;
+ @ElementCollection
+ @CollectionTable(name = "customer_address")
+ private List
addressList;
+
+ public Customer() {
+ }
+
+ public Customer(Long customerId, String name, String lastName, List addressList) {
+ this.customerId = customerId;
+ this.name = name;
+ this.lastName = lastName;
+ this.addressList = addressList;
+ }
+
+ public Long getCustomerId() {
+ return customerId;
+ }
+
+ public void setCustomerId(Long customerId) {
+ this.customerId = customerId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public List getAddressList() {
+ return addressList;
+ }
+
+ public void setAddressList(List addressList) {
+ this.addressList = addressList;
+ }
+}
diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/Individual.java b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/Individual.java
new file mode 100644
index 0000000000..e491c09eb5
--- /dev/null
+++ b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/Individual.java
@@ -0,0 +1,49 @@
+package com.baeldung.hibernate.pessimisticlocking;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+
+@Entity
+@Inheritance(strategy = InheritanceType.JOINED)
+public class Individual {
+
+ @Id
+ private Long id;
+ private String name;
+ private String lastName;
+
+ public Individual(Long id, String name, String lastName) {
+ this.id = id;
+ this.name = name;
+ this.lastName = lastName;
+ }
+
+ public Individual() {
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+}
diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingCourse.java b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingCourse.java
new file mode 100644
index 0000000000..aea7d5fc87
--- /dev/null
+++ b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingCourse.java
@@ -0,0 +1,47 @@
+package com.baeldung.hibernate.pessimisticlocking;
+
+import javax.persistence.*;
+
+@Entity
+public class PessimisticLockingCourse {
+
+ @Id
+ private Long courseId;
+ private String name;
+ @ManyToOne
+ @JoinTable(name = "student_course")
+ private PessimisticLockingStudent student;
+
+ public PessimisticLockingCourse(Long courseId, String name, PessimisticLockingStudent student) {
+ this.courseId = courseId;
+ this.name = name;
+ this.student = student;
+ }
+
+ public PessimisticLockingCourse() {
+ }
+
+ public Long getCourseId() {
+ return courseId;
+ }
+
+ public void setCourseId(Long courseId) {
+ this.courseId = courseId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public PessimisticLockingStudent getStudent() {
+ return student;
+ }
+
+ public void setStudent(PessimisticLockingStudent students) {
+ this.student = students;
+ }
+}
diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingEmployee.java b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingEmployee.java
new file mode 100644
index 0000000000..a1328cbdad
--- /dev/null
+++ b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingEmployee.java
@@ -0,0 +1,27 @@
+package com.baeldung.hibernate.pessimisticlocking;
+
+import javax.persistence.Entity;
+import java.math.BigDecimal;
+
+@Entity
+public class PessimisticLockingEmployee extends Individual {
+
+ private BigDecimal salary;
+
+ public PessimisticLockingEmployee(Long id, String name, String lastName, BigDecimal salary) {
+ super(id, name, lastName);
+ this.salary = salary;
+ }
+
+ public PessimisticLockingEmployee() {
+ super();
+ }
+
+ public BigDecimal getSalary() {
+ return salary;
+ }
+
+ public void setSalary(BigDecimal average) {
+ this.salary = average;
+ }
+}
diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingStudent.java b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingStudent.java
new file mode 100644
index 0000000000..e6c5f476b4
--- /dev/null
+++ b/hibernate5/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingStudent.java
@@ -0,0 +1,46 @@
+package com.baeldung.hibernate.pessimisticlocking;
+
+import javax.persistence.*;
+import java.util.List;
+
+@Entity
+public class PessimisticLockingStudent {
+
+ @Id
+ private Long id;
+ private String name;
+ @OneToMany(mappedBy = "student")
+ private List courses;
+
+ public PessimisticLockingStudent(Long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public PessimisticLockingStudent() {
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List getCourses() {
+ return courses;
+ }
+
+ public void setCourses(List courses) {
+ this.courses = courses;
+ }
+}
diff --git a/hibernate5/src/test/java/com/baeldung/hibernate/pessimisticlocking/BasicPessimisticLockingIntegrationTest.java b/hibernate5/src/test/java/com/baeldung/hibernate/pessimisticlocking/BasicPessimisticLockingIntegrationTest.java
new file mode 100644
index 0000000000..f416c11d1f
--- /dev/null
+++ b/hibernate5/src/test/java/com/baeldung/hibernate/pessimisticlocking/BasicPessimisticLockingIntegrationTest.java
@@ -0,0 +1,151 @@
+package com.baeldung.hibernate.pessimisticlocking;
+
+import com.baeldung.hibernate.HibernateUtil;
+import com.vividsolutions.jts.util.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.persistence.*;
+import java.io.IOException;
+import java.util.Arrays;
+
+public class BasicPessimisticLockingIntegrationTest {
+
+ @BeforeClass
+ public static void setUp() throws IOException {
+ EntityManager entityManager = getEntityManagerWithOpenTransaction();
+ PessimisticLockingStudent student = new PessimisticLockingStudent(1L, "JOHN");
+ PessimisticLockingCourse course = new PessimisticLockingCourse(1L, "MATH", student);
+ student.setCourses(Arrays.asList(course));
+ entityManager.persist(course);
+ entityManager.persist(student);
+ entityManager.getTransaction()
+ .commit();
+ entityManager.close();
+ }
+
+ @Test
+ public void givenFoundRecordWithPessimisticRead_whenFindingNewOne_PessimisticLockExceptionThrown() {
+ try {
+ EntityManager entityManager = getEntityManagerWithOpenTransaction();
+ entityManager.find(PessimisticLockingStudent.class, 1L, LockModeType.PESSIMISTIC_READ);
+
+ EntityManager entityManager2 = getEntityManagerWithOpenTransaction();
+ entityManager2.find(PessimisticLockingStudent.class, 1L, LockModeType.PESSIMISTIC_READ);
+
+ entityManager.close();
+ entityManager2.close();
+ } catch (Exception e) {
+ Assert.isTrue(e instanceof PessimisticLockException);
+ }
+ }
+
+ @Test
+ public void givenRecordWithPessimisticReadQuery_whenQueryingNewOne_PessimisticLockExceptionThrown() throws IOException {
+ try {
+ EntityManager entityManager = getEntityManagerWithOpenTransaction();
+ Query query = entityManager.createQuery("from Student where studentId = :studentId");
+ query.setParameter("studentId", 1L);
+ query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
+ query.getResultList();
+
+ EntityManager entityManager2 = getEntityManagerWithOpenTransaction();
+ Query query2 = entityManager2.createQuery("from Student where studentId = :studentId");
+ query2.setParameter("studentId", 1L);
+ query2.setLockMode(LockModeType.PESSIMISTIC_READ);
+ query2.getResultList();
+
+ entityManager.close();
+ entityManager2.close();
+ } catch (Exception e) {
+ Assert.isTrue(e instanceof PessimisticLockException);
+ }
+ }
+
+ @Test
+ public void givenRecordWithPessimisticReadLock_whenFindingNewOne_PessimisticLockExceptionThrown() {
+ try {
+ EntityManager entityManager = getEntityManagerWithOpenTransaction();
+ PessimisticLockingStudent resultStudent = entityManager.find(PessimisticLockingStudent.class, 1L);
+ entityManager.lock(resultStudent, LockModeType.PESSIMISTIC_READ);
+
+ EntityManager entityManager2 = getEntityManagerWithOpenTransaction();
+ entityManager2.find(PessimisticLockingStudent.class, 1L, LockModeType.PESSIMISTIC_FORCE_INCREMENT);
+
+ entityManager.close();
+ entityManager2.close();
+ } catch (Exception e) {
+ Assert.isTrue(e instanceof PessimisticLockException);
+ }
+ }
+
+ @Test
+ public void givenRecordAndRefreshWithPessimisticRead_whenFindingWithPessimisticWrite_PessimisticLockExceptionThrown() {
+ try {
+ EntityManager entityManager = getEntityManagerWithOpenTransaction();
+ PessimisticLockingStudent resultStudent = entityManager.find(PessimisticLockingStudent.class, 1L);
+ entityManager.refresh(resultStudent, LockModeType.PESSIMISTIC_FORCE_INCREMENT);
+
+ EntityManager entityManager2 = getEntityManagerWithOpenTransaction();
+ entityManager2.find(PessimisticLockingStudent.class, 1L, LockModeType.PESSIMISTIC_WRITE);
+
+ entityManager.close();
+ entityManager2.close();
+ } catch (Exception e) {
+ Assert.isTrue(e instanceof PessimisticLockException);
+ }
+ }
+
+ @Test
+ public void givenRecordWithPessimisticRead_whenUpdatingRecord_PessimisticLockExceptionThrown() {
+ try {
+ EntityManager entityManager = getEntityManagerWithOpenTransaction();
+ PessimisticLockingStudent resultStudent = entityManager.find(PessimisticLockingStudent.class, 1L);
+ entityManager.refresh(resultStudent, LockModeType.PESSIMISTIC_READ);
+
+ EntityManager entityManager2 = getEntityManagerWithOpenTransaction();
+ PessimisticLockingStudent resultStudent2 = entityManager2.find(PessimisticLockingStudent.class, 1L);
+ resultStudent2.setName("Change");
+ entityManager2.persist(resultStudent2);
+ entityManager2.getTransaction()
+ .commit();
+
+ entityManager.close();
+ entityManager2.close();
+ } catch (Exception e) {
+ Assert.isTrue(e instanceof PessimisticLockException);
+ }
+ }
+
+ @Test
+ public void givenRecordWithPessimisticWrite_whenUpdatingRecord_PessimisticLockExceptionThrown() {
+ try {
+ EntityManager entityManager = getEntityManagerWithOpenTransaction();
+ PessimisticLockingStudent resultStudent = entityManager.find(PessimisticLockingStudent.class, 1L);
+ entityManager.refresh(resultStudent, LockModeType.PESSIMISTIC_WRITE);
+
+ EntityManager entityManager2 = getEntityManagerWithOpenTransaction();
+ PessimisticLockingStudent resultStudent2 = entityManager2.find(PessimisticLockingStudent.class, 1L);
+ resultStudent2.setName("Change");
+ entityManager2.persist(resultStudent2);
+ entityManager2.getTransaction()
+ .commit();
+
+ entityManager.close();
+ entityManager2.close();
+ } catch (Exception e) {
+ Assert.isTrue(e instanceof PessimisticLockException);
+ }
+ }
+
+ protected static EntityManager getEntityManagerWithOpenTransaction() throws IOException {
+ String propertyFileName = "hibernate-pessimistic-locking.properties";
+ EntityManager entityManager = HibernateUtil.getSessionFactory(propertyFileName)
+ .openSession();
+ entityManager.getTransaction()
+ .begin();
+
+ return entityManager;
+ }
+
+}
diff --git a/hibernate5/src/test/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockScopesIntegrationTest.java b/hibernate5/src/test/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockScopesIntegrationTest.java
new file mode 100644
index 0000000000..ac56ab7133
--- /dev/null
+++ b/hibernate5/src/test/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockScopesIntegrationTest.java
@@ -0,0 +1,115 @@
+package com.baeldung.hibernate.pessimisticlocking;
+
+import com.baeldung.hibernate.HibernateUtil;
+import org.junit.Test;
+
+import javax.persistence.EntityManager;
+import javax.persistence.LockModeType;
+import javax.persistence.PessimisticLockScope;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public class PessimisticLockScopesIntegrationTest {
+
+ @Test
+ public void givenEclipseEntityWithJoinInheritance_whenNormalLock_thenShouldChildAndParentEntity() throws IOException {
+ EntityManager em = getEntityManagerWithOpenTransaction();
+ PessimisticLockingEmployee employee = new PessimisticLockingEmployee(1L, "JOHN", "SMITH", new BigDecimal(4.5));
+ em.persist(employee);
+ em.getTransaction()
+ .commit();
+ em.close();
+
+ // NORMAL SCOPE
+ EntityManager em2 = getEntityManagerWithOpenTransaction();
+ PessimisticLockingEmployee foundEmployee = em2.find(PessimisticLockingEmployee.class, 1L, LockModeType.PESSIMISTIC_WRITE);
+ em2.getTransaction()
+ .rollback();
+
+ // EXTENDED SCOPE
+ Map map = new HashMap<>();
+ map.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED);
+
+ EntityManager em3 = getEntityManagerWithOpenTransaction();
+ foundEmployee = em3.find(PessimisticLockingEmployee.class, 1L, LockModeType.PESSIMISTIC_WRITE, map);
+ em3.getTransaction()
+ .rollback();
+
+ em2.close();
+ em3.close();
+ }
+
+ @Test
+ public void givenEntityWithElementCollection_whenLock_thenHibernateExtendedScopeLockOnlyOwningEntity() throws IOException {
+ EntityManager em = getEntityManagerWithOpenTransaction();
+ Address address = new Address("Poland", "Warsaw");
+ Customer customer = new Customer(1L, "JOE", "DOE", Arrays.asList(address));
+ em.persist(customer);
+ em.getTransaction()
+ .commit();
+ em.close();
+
+ // NORMAL SCOPE
+ EntityManager em2 = getEntityManagerWithOpenTransaction();
+ Customer foundCustomer = em2.find(Customer.class, 1L, LockModeType.PESSIMISTIC_WRITE);
+ em2.getTransaction()
+ .rollback();
+
+ // EXTENDED SCOPE
+ Map map = new HashMap<>();
+ map.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED);
+
+ EntityManager em3 = getEntityManagerWithOpenTransaction();
+ foundCustomer = em3.find(Customer.class, 1L, LockModeType.PESSIMISTIC_WRITE, map);
+ em2.getTransaction()
+ .rollback();
+
+ em2.close();
+ em3.close();
+ }
+
+ @Test
+ public void givenEntityWithOneToMany_whenLock_thenHibernateExtendedScopeLockOnlyOwningEntity() throws IOException {
+ EntityManager em = getEntityManagerWithOpenTransaction();
+ PessimisticLockingStudent student = new PessimisticLockingStudent(1L, "JOE");
+ PessimisticLockingCourse course = new PessimisticLockingCourse(1L, "COURSE", student);
+ student.setCourses(Arrays.asList(course));
+ em.persist(course);
+ em.persist(student);
+ em.getTransaction()
+ .commit();
+ em.close();
+
+ // NORMAL SCOPE
+ EntityManager em2 = getEntityManagerWithOpenTransaction();
+ PessimisticLockingCourse foundCourse = em2.find(PessimisticLockingCourse.class, 1L, LockModeType.PESSIMISTIC_WRITE);
+ em2.getTransaction()
+ .rollback();
+
+ // EXTENDED SCOPE
+ Map map = new HashMap<>();
+ map.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED);
+
+ EntityManager em3 = getEntityManagerWithOpenTransaction();
+ foundCourse = em3.find(PessimisticLockingCourse.class, 1L, LockModeType.PESSIMISTIC_WRITE, map);
+ em3.getTransaction()
+ .rollback();
+
+ em2.close();
+ em3.close();
+ }
+
+ protected EntityManager getEntityManagerWithOpenTransaction() throws IOException {
+ String propertyFileName = "hibernate-pessimistic-locking.properties";
+ EntityManager entityManager = HibernateUtil.getSessionFactory(propertyFileName)
+ .openSession();
+ entityManager.getTransaction()
+ .begin();
+
+ return entityManager;
+ }
+
+}
diff --git a/hibernate5/src/test/resources/hibernate-pessimistic-locking.properties b/hibernate5/src/test/resources/hibernate-pessimistic-locking.properties
new file mode 100644
index 0000000000..c76bd3358b
--- /dev/null
+++ b/hibernate5/src/test/resources/hibernate-pessimistic-locking.properties
@@ -0,0 +1,8 @@
+hibernate.connection.driver_class=org.h2.Driver
+hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1;LOCK_TIMEOUT=100;MVCC=FALSE
+hibernate.connection.username=sa
+hibernate.connection.autocommit=true
+hibernate.dialect=org.hibernate.dialect.H2Dialect
+
+hibernate.show_sql=true
+hibernate.hbm2ddl.auto=create-drop
\ No newline at end of file
diff --git a/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Address.java b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Address.java
new file mode 100644
index 0000000000..b62889208c
--- /dev/null
+++ b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Address.java
@@ -0,0 +1,34 @@
+package com.baeldung.eclipselink.springdata.pessimisticlocking;
+
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class Address {
+
+ private String country;
+ private String city;
+
+ public Address(String country, String city) {
+ this.country = country;
+ this.city = city;
+ }
+
+ public Address() {
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+}
diff --git a/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Course.java b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Course.java
new file mode 100644
index 0000000000..8d90659f3e
--- /dev/null
+++ b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Course.java
@@ -0,0 +1,50 @@
+package com.baeldung.eclipselink.springdata.pessimisticlocking;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToOne;
+
+@Entity
+public class Course {
+
+ @Id
+ private Long courseId;
+ private String name;
+ @ManyToOne
+ @JoinTable(name = "student_course")
+ private Student student;
+
+ public Course(Long courseId, String name, Student student) {
+ this.courseId = courseId;
+ this.name = name;
+ this.student = student;
+ }
+
+ public Course() {
+ }
+
+ public Long getCourseId() {
+ return courseId;
+ }
+
+ public void setCourseId(Long courseId) {
+ this.courseId = courseId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Student getStudent() {
+ return student;
+ }
+
+ public void setStudent(Student students) {
+ this.student = students;
+ }
+}
diff --git a/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Customer.java b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Customer.java
new file mode 100644
index 0000000000..f06a676de8
--- /dev/null
+++ b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Customer.java
@@ -0,0 +1,61 @@
+package com.baeldung.eclipselink.springdata.pessimisticlocking;
+
+import javax.persistence.CollectionTable;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.util.List;
+
+@Entity
+public class Customer {
+
+ @Id
+ private Long customerId;
+ private String name;
+ private String lastName;
+ @ElementCollection
+ @CollectionTable(name = "customer_address")
+ private List addressList;
+
+ public Customer() {
+ }
+
+ public Customer(Long customerId, String name, String lastName, List addressList) {
+ this.customerId = customerId;
+ this.name = name;
+ this.lastName = lastName;
+ this.addressList = addressList;
+ }
+
+ public Long getCustomerId() {
+ return customerId;
+ }
+
+ public void setCustomerId(Long customerId) {
+ this.customerId = customerId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public List getAddressList() {
+ return addressList;
+ }
+
+ public void setAddressList(List addressList) {
+ this.addressList = addressList;
+ }
+}
diff --git a/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Employee.java b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Employee.java
new file mode 100644
index 0000000000..d09b123225
--- /dev/null
+++ b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Employee.java
@@ -0,0 +1,27 @@
+package com.baeldung.eclipselink.springdata.pessimisticlocking;
+
+import javax.persistence.Entity;
+import java.math.BigDecimal;
+
+@Entity
+public class Employee extends Individual {
+
+ private BigDecimal salary;
+
+ public Employee(Long id, String name, String lastName, BigDecimal salary) {
+ super(id, name, lastName);
+ this.salary = salary;
+ }
+
+ public Employee() {
+ super();
+ }
+
+ public BigDecimal getSalary() {
+ return salary;
+ }
+
+ public void setSalary(BigDecimal average) {
+ this.salary = average;
+ }
+}
diff --git a/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Individual.java b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Individual.java
new file mode 100644
index 0000000000..7edaaace54
--- /dev/null
+++ b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Individual.java
@@ -0,0 +1,49 @@
+package com.baeldung.eclipselink.springdata.pessimisticlocking;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+
+@Entity
+@Inheritance(strategy = InheritanceType.JOINED)
+public class Individual {
+
+ @Id
+ private Long id;
+ private String name;
+ private String lastName;
+
+ public Individual(Long id, String name, String lastName) {
+ this.id = id;
+ this.name = name;
+ this.lastName = lastName;
+ }
+
+ public Individual() {
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+}
diff --git a/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Student.java b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Student.java
new file mode 100644
index 0000000000..f613aab0f6
--- /dev/null
+++ b/persistence-modules/spring-data-eclipselink/src/main/java/com/baeldung/eclipselink/springdata/pessimisticlocking/Student.java
@@ -0,0 +1,48 @@
+package com.baeldung.eclipselink.springdata.pessimisticlocking;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import java.util.List;
+
+@Entity
+public class Student {
+
+ @Id
+ private Long id;
+ private String name;
+ @OneToMany(mappedBy = "student")
+ private List courses;
+
+ public Student(Long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public Student() {
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List getCourses() {
+ return courses;
+ }
+
+ public void setCourses(List courses) {
+ this.courses = courses;
+ }
+}
diff --git a/persistence-modules/spring-data-eclipselink/src/main/resources/application.properties b/persistence-modules/spring-data-eclipselink/src/main/resources/application.properties
index 549c0b4ada..5874482e7a 100644
--- a/persistence-modules/spring-data-eclipselink/src/main/resources/application.properties
+++ b/persistence-modules/spring-data-eclipselink/src/main/resources/application.properties
@@ -1,2 +1,2 @@
-spring.datasource.url=jdbc:h2:mem:test
+spring.datasource.url=jdbc:h2:mem:test;MVCC=FALSE;LOCK_TIMEOUT=100;
spring.jpa.show-sql=true
\ No newline at end of file
diff --git a/persistence-modules/spring-data-eclipselink/src/test/java/com/baeldung/eclipselink/springdata/pessimisticlocking/PessimisticLockScopesIntegrationTest.java b/persistence-modules/spring-data-eclipselink/src/test/java/com/baeldung/eclipselink/springdata/pessimisticlocking/PessimisticLockScopesIntegrationTest.java
new file mode 100644
index 0000000000..6ee40fac9a
--- /dev/null
+++ b/persistence-modules/spring-data-eclipselink/src/test/java/com/baeldung/eclipselink/springdata/pessimisticlocking/PessimisticLockScopesIntegrationTest.java
@@ -0,0 +1,118 @@
+package com.baeldung.eclipselink.springdata.pessimisticlocking;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class PessimisticLockScopesIntegrationTest {
+
+ @Autowired
+ EntityManagerFactory entityManagerFactory;
+
+ @Test
+ public void givenEntityWithJoinInheritance_whenLock_thenNormalAndExtendScopesLockParentAndChildEntity() {
+ EntityManager em = getEntityManagerWithOpenTransaction();
+ Employee employee = new Employee(1L, "JOE", "DOE", new BigDecimal(4.5));
+ em.persist(employee);
+ em.getTransaction()
+ .commit();
+ em.close();
+
+ // NORMAL SCOPE
+ EntityManager em2 = getEntityManagerWithOpenTransaction();
+ Employee foundEmployee = em2.find(Employee.class, 1L, LockModeType.PESSIMISTIC_WRITE);
+ em2.getTransaction()
+ .rollback();
+
+ // EXTENDED SCOPE
+ Map map = new HashMap<>();
+ map.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED);
+
+ EntityManager em3 = getEntityManagerWithOpenTransaction();
+ foundEmployee = em3.find(Employee.class, 1L, LockModeType.PESSIMISTIC_WRITE, map);
+ em3.getTransaction()
+ .rollback();
+
+ em2.close();
+ em3.close();
+ }
+
+ @Test
+ public void givenEntityWithElementCollection_whenLock_thenExtendScopeLocksAlsoCollectionTable() {
+ EntityManager em = getEntityManagerWithOpenTransaction();
+ Address address = new Address("Poland", "Warsaw");
+ Customer customer = new Customer(1L, "JOHN", "SMITH", Arrays.asList(address));
+ em.persist(customer);
+ em.getTransaction()
+ .commit();
+ em.close();
+
+ // NORMAL SCOPE
+ EntityManager em2 = getEntityManagerWithOpenTransaction();
+ Customer foundCustomer = em2.find(Customer.class, 1L, LockModeType.PESSIMISTIC_WRITE);
+ em2.getTransaction()
+ .rollback();
+
+ // EXTENDED SCOPE
+ Map map = new HashMap<>();
+ map.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED);
+
+ EntityManager em3 = getEntityManagerWithOpenTransaction();
+ foundCustomer = em3.find(Customer.class, 1L, LockModeType.PESSIMISTIC_WRITE, map);
+ em3.getTransaction()
+ .rollback();
+
+ em2.close();
+ em3.close();
+ }
+
+ @Test
+ public void givenEclipseEntityWithOneToMany_whenLock_thenExtendedLockAlsoJoinTable() {
+ EntityManager em = getEntityManagerWithOpenTransaction();
+ Student student = new Student(1L, "JOE");
+ Course course = new Course(1L, "COURSE", student);
+ student.setCourses(Arrays.asList(course));
+ em.persist(course);
+ em.persist(student);
+ em.getTransaction()
+ .commit();
+ em.close();
+
+ // NORMAL SCOPE
+ EntityManager em2 = getEntityManagerWithOpenTransaction();
+ Course foundCourse = em2.find(Course.class, 1L, LockModeType.PESSIMISTIC_WRITE);
+ em2.getTransaction()
+ .rollback();
+
+ // EXTENDED SCOPE
+ Map map = new HashMap<>();
+ map.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED);
+
+ EntityManager em3 = getEntityManagerWithOpenTransaction();
+ foundCourse = em3.find(Course.class, 1L, LockModeType.PESSIMISTIC_WRITE, map);
+ em3.getTransaction()
+ .rollback();
+
+ em2.close();
+ em3.close();
+ }
+
+ protected EntityManager getEntityManagerWithOpenTransaction() {
+ EntityManager entityManager = entityManagerFactory.createEntityManager();
+ entityManager.getTransaction()
+ .begin();
+ return entityManager;
+ }
+}