diff --git a/persistence-modules/hibernate5-jpa/README.md b/persistence-modules/hibernate5-jpa/README.md
new file mode 100644
index 0000000000..bffba85d54
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/README.md
@@ -0,0 +1,16 @@
+## Hibernate 5
+
+This module contains articles about Hibernate 5.
+
+### Relevant articles:
+
+- [JPA Attribute Converters](http://www.baeldung.com/jpa-attribute-converters)
+- [Pessimistic Locking in JPA](http://www.baeldung.com/jpa-pessimistic-locking)
+- [Bootstrapping JPA Programmatically in Java](http://www.baeldung.com/java-bootstrap-jpa)
+- [Optimistic Locking in JPA](http://www.baeldung.com/jpa-optimistic-locking)
+- [Criteria API – An Example of IN Expressions](https://www.baeldung.com/jpa-criteria-api-in-expressions)
+- [One-to-One Relationship in JPA](https://www.baeldung.com/jpa-one-to-one)
+- [Enabling Transaction Locks in Spring Data JPA](https://www.baeldung.com/java-jpa-transaction-locks)
+- [TransactionRequiredException Error](https://www.baeldung.com/jpa-transaction-required-exception)
+- [FetchMode in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-fetchmode)
+- [JPA/Hibernate Persistence Context](https://www.baeldung.com/jpa-hibernate-persistence-context)
diff --git a/persistence-modules/hibernate5-jpa/pom.xml b/persistence-modules/hibernate5-jpa/pom.xml
new file mode 100644
index 0000000000..b181fff36b
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/pom.xml
@@ -0,0 +1,95 @@
+
+
+ 4.0.0
+ hibernate5-jpa
+ 0.0.1-SNAPSHOT
+ hibernate5-jpa
+
+
+ com.baeldung
+ persistence-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ org.hibernate
+ hibernate-core
+ ${hibernate.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring-boot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+ ${spring-boot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+ ${spring-boot.version}
+
+
+ com.zaxxer
+ HikariCP
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ ${spring-boot.version}
+
+
+ org.assertj
+ assertj-core
+ ${assertj-core.version}
+ test
+
+
+ com.h2database
+ h2
+ ${h2.version}
+
+
+ org.hibernate
+ hibernate-spatial
+ ${hibernate.version}
+
+
+ mysql
+ mysql-connector-java
+ ${mysql.version}
+
+
+ ch.vorburger.mariaDB4j
+ mariaDB4j
+ ${mariaDB4j.version}
+
+
+ org.hibernate
+ hibernate-testing
+ ${hibernate.version}
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ ${openjdk-jmh.version}
+
+
+
+
+ 5.3.7.Final
+ 6.0.6
+ 2.2.3
+ 3.8.0
+ 1.21
+ 2.1.7.RELEASE
+
+
+
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/HibernateUtil.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/HibernateUtil.java
new file mode 100644
index 0000000000..cf59fe4855
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/HibernateUtil.java
@@ -0,0 +1,89 @@
+package com.baeldung.hibernate;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+
+import org.apache.commons.lang3.StringUtils;
+import org.hibernate.SessionFactory;
+import org.hibernate.boot.Metadata;
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.service.ServiceRegistry;
+
+import com.baeldung.hibernate.entities.DeptEmployee;
+import com.baeldung.hibernate.optimisticlocking.OptimisticLockingCourse;
+import com.baeldung.hibernate.optimisticlocking.OptimisticLockingStudent;
+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.Person;
+import com.baeldung.hibernate.pojo.Post;
+import com.baeldung.hibernate.pojo.Student;
+
+public class HibernateUtil {
+ private static String PROPERTY_FILE_NAME;
+
+ public static SessionFactory getSessionFactory() throws IOException {
+ return getSessionFactory(null);
+ }
+
+ public static SessionFactory getSessionFactory(String propertyFileName) throws IOException {
+ PROPERTY_FILE_NAME = propertyFileName;
+ ServiceRegistry serviceRegistry = configureServiceRegistry();
+ return makeSessionFactory(serviceRegistry);
+ }
+
+ public static SessionFactory getSessionFactoryByProperties(Properties properties) throws IOException {
+ ServiceRegistry serviceRegistry = configureServiceRegistry(properties);
+ return makeSessionFactory(serviceRegistry);
+ }
+
+ private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) {
+ MetadataSources metadataSources = new MetadataSources(serviceRegistry);
+
+ metadataSources.addPackage("com.baeldung.hibernate.pojo");
+ metadataSources.addAnnotatedClass(Person.class);
+ metadataSources.addAnnotatedClass(Student.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);
+ metadataSources.addAnnotatedClass(DeptEmployee.class);
+ metadataSources.addAnnotatedClass(com.baeldung.hibernate.entities.Department.class);
+ metadataSources.addAnnotatedClass(OptimisticLockingCourse.class);
+ metadataSources.addAnnotatedClass(OptimisticLockingStudent.class);
+ metadataSources.addAnnotatedClass(Post.class);
+
+ Metadata metadata = metadataSources.getMetadataBuilder()
+ .build();
+
+ return metadata.getSessionFactoryBuilder()
+ .build();
+
+ }
+
+ private static ServiceRegistry configureServiceRegistry() throws IOException {
+ return configureServiceRegistry(getProperties());
+ }
+
+ private static ServiceRegistry configureServiceRegistry(Properties properties) throws IOException {
+ return new StandardServiceRegistryBuilder().applySettings(properties)
+ .build();
+ }
+
+ public static Properties getProperties() throws IOException {
+ Properties properties = new Properties();
+ URL propertiesURL = Thread.currentThread()
+ .getContextClassLoader()
+ .getResource(StringUtils.defaultString(PROPERTY_FILE_NAME, "hibernate.properties"));
+ try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) {
+ properties.load(inputStream);
+ }
+ return properties;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/UnsupportedTenancyException.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/UnsupportedTenancyException.java
new file mode 100644
index 0000000000..99d9505ea3
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/UnsupportedTenancyException.java
@@ -0,0 +1,8 @@
+package com.baeldung.hibernate;
+
+public class UnsupportedTenancyException extends Exception {
+ public UnsupportedTenancyException (String message) {
+ super(message);
+ }
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java
new file mode 100644
index 0000000000..506e674984
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java
@@ -0,0 +1,61 @@
+package com.baeldung.hibernate.converters;
+
+import javax.persistence.AttributeConverter;
+import javax.persistence.Converter;
+
+import com.baeldung.hibernate.pojo.PersonName;
+
+@Converter
+public class PersonNameConverter implements AttributeConverter {
+
+ private static final String SEPARATOR = ", ";
+
+ @Override
+ public String convertToDatabaseColumn(PersonName personName) {
+ if (personName == null) {
+ return null;
+ }
+
+ StringBuilder sb = new StringBuilder();
+ if (personName.getSurname() != null && !personName.getSurname()
+ .isEmpty()) {
+ sb.append(personName.getSurname());
+ sb.append(SEPARATOR);
+ }
+
+ if (personName.getName() != null && !personName.getName()
+ .isEmpty()) {
+ sb.append(personName.getName());
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public PersonName convertToEntityAttribute(String dbPersonName) {
+ if (dbPersonName == null || dbPersonName.isEmpty()) {
+ return null;
+ }
+
+ String[] pieces = dbPersonName.split(SEPARATOR);
+
+ if (pieces == null || pieces.length == 0) {
+ return null;
+ }
+
+ PersonName personName = new PersonName();
+ String firstPiece = !pieces[0].isEmpty() ? pieces[0] : null;
+ if (dbPersonName.contains(SEPARATOR)) {
+ personName.setSurname(firstPiece);
+
+ if (pieces.length >= 2 && pieces[1] != null && !pieces[1].isEmpty()) {
+ personName.setName(pieces[1]);
+ }
+ } else {
+ personName.setName(firstPiece);
+ }
+
+ return personName;
+ }
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/entities/Department.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/entities/Department.java
new file mode 100644
index 0000000000..ff94f4f849
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/entities/Department.java
@@ -0,0 +1,45 @@
+package com.baeldung.hibernate.entities;
+
+import java.util.List;
+
+import javax.persistence.*;
+
+@Entity
+public class Department {
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE)
+ private long id;
+
+ private String name;
+
+ @OneToMany(mappedBy="department")
+ private List employees;
+
+ public Department(String name) {
+ this.name = name;
+ }
+
+ 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 getEmployees() {
+ return employees;
+ }
+
+ public void setEmployees(List employees) {
+ this.employees = employees;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/entities/DeptEmployee.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/entities/DeptEmployee.java
new file mode 100644
index 0000000000..6510e70650
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/entities/DeptEmployee.java
@@ -0,0 +1,83 @@
+package com.baeldung.hibernate.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+
+@org.hibernate.annotations.NamedQueries({ @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindByEmployeeNumber", query = "from DeptEmployee where employeeNumber = :employeeNo"),
+ @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindAllByDesgination", query = "from DeptEmployee where designation = :designation"),
+ @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_UpdateEmployeeDepartment", query = "Update DeptEmployee set department = :newDepartment where employeeNumber = :employeeNo"),
+ @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindAllByDepartment", query = "from DeptEmployee where department = :department", timeout = 1, fetchSize = 10) })
+@org.hibernate.annotations.NamedNativeQueries({ @org.hibernate.annotations.NamedNativeQuery(name = "DeptEmployee_FindByEmployeeName", query = "select * from deptemployee emp where name=:name", resultClass = DeptEmployee.class),
+ @org.hibernate.annotations.NamedNativeQuery(name = "DeptEmployee_UpdateEmployeeDesignation", query = "call UPDATE_EMPLOYEE_DESIGNATION(:employeeNumber, :newDesignation)", resultClass = DeptEmployee.class) })
+@Entity
+public class DeptEmployee {
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE)
+ private long id;
+
+ private String employeeNumber;
+
+ private String title;
+
+ private String name;
+
+ @ManyToOne
+ private Department department;
+
+ public DeptEmployee(String name, String employeeNumber, Department department) {
+ this.name = name;
+ this.employeeNumber = employeeNumber;
+ this.department = department;
+ }
+
+ public DeptEmployee(String name, String employeeNumber, String title, Department department) {
+ super();
+ this.name = name;
+ this.employeeNumber = employeeNumber;
+ this.title = title;
+ this.department = department;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getEmployeeNumber() {
+ return employeeNumber;
+ }
+
+ public void setEmployeeNumber(String employeeNumber) {
+ this.employeeNumber = employeeNumber;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Department getDepartment() {
+ return department;
+ }
+
+ public void setDepartment(Department department) {
+ this.department = department;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/application/Application.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/application/Application.java
new file mode 100644
index 0000000000..f7b8e6bf6d
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/application/Application.java
@@ -0,0 +1,34 @@
+package com.baeldung.hibernate.jpabootstrap.application;
+
+import com.baeldung.hibernate.jpabootstrap.config.JpaEntityManagerFactory;
+import com.baeldung.hibernate.jpabootstrap.entities.User;
+import javax.persistence.EntityManager;
+
+public class Application {
+
+ public static void main(String[] args) {
+ EntityManager entityManager = getJpaEntityManager();
+ User user = entityManager.find(User.class, 1);
+ System.out.println(user);
+ entityManager.getTransaction().begin();
+ user.setName("John");
+ user.setEmail("john@domain.com");
+ entityManager.merge(user);
+ entityManager.getTransaction().commit();
+ entityManager.getTransaction().begin();
+ entityManager.persist(new User("Monica", "monica@domain.com"));
+ entityManager.getTransaction().commit();
+
+ // additional CRUD operations
+
+ }
+
+ private static class EntityManagerHolder {
+ private static final EntityManager ENTITY_MANAGER = new JpaEntityManagerFactory(
+ new Class[]{User.class}).getEntityManager();
+ }
+
+ public static EntityManager getJpaEntityManager() {
+ return EntityManagerHolder.ENTITY_MANAGER;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/config/HibernatePersistenceUnitInfo.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/config/HibernatePersistenceUnitInfo.java
new file mode 100644
index 0000000000..3852b44b64
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/config/HibernatePersistenceUnitInfo.java
@@ -0,0 +1,131 @@
+package com.baeldung.hibernate.jpabootstrap.config;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import javax.sql.DataSource;
+import javax.persistence.SharedCacheMode;
+import javax.persistence.ValidationMode;
+import javax.persistence.spi.ClassTransformer;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import org.hibernate.jpa.HibernatePersistenceProvider;
+
+public class HibernatePersistenceUnitInfo implements PersistenceUnitInfo {
+
+ public static final String JPA_VERSION = "2.1";
+ private final String persistenceUnitName;
+ private PersistenceUnitTransactionType transactionType = PersistenceUnitTransactionType.RESOURCE_LOCAL;
+ private final List managedClassNames;
+ private final List mappingFileNames = new ArrayList<>();
+ private final Properties properties;
+ private DataSource jtaDataSource;
+ private DataSource nonjtaDataSource;
+ private final List transformers = new ArrayList<>();
+
+ public HibernatePersistenceUnitInfo(String persistenceUnitName, List managedClassNames, Properties properties) {
+ this.persistenceUnitName = persistenceUnitName;
+ this.managedClassNames = managedClassNames;
+ this.properties = properties;
+ }
+
+ @Override
+ public String getPersistenceUnitName() {
+ return persistenceUnitName;
+ }
+
+ @Override
+ public String getPersistenceProviderClassName() {
+ return HibernatePersistenceProvider.class.getName();
+ }
+
+ @Override
+ public PersistenceUnitTransactionType getTransactionType() {
+ return transactionType;
+ }
+
+ public HibernatePersistenceUnitInfo setJtaDataSource(DataSource jtaDataSource) {
+ this.jtaDataSource = jtaDataSource;
+ this.nonjtaDataSource = null;
+ transactionType = PersistenceUnitTransactionType.JTA;
+ return this;
+ }
+
+ @Override
+ public DataSource getJtaDataSource() {
+ return jtaDataSource;
+ }
+
+ public HibernatePersistenceUnitInfo setNonJtaDataSource(DataSource nonJtaDataSource) {
+ this.nonjtaDataSource = nonJtaDataSource;
+ this.jtaDataSource = null;
+ transactionType = PersistenceUnitTransactionType.RESOURCE_LOCAL;
+ return this;
+ }
+
+ @Override
+ public DataSource getNonJtaDataSource() {
+ return nonjtaDataSource;
+ }
+
+ @Override
+ public List getMappingFileNames() {
+ return mappingFileNames;
+ }
+
+ @Override
+ public List getJarFileUrls() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public URL getPersistenceUnitRootUrl() {
+ return null;
+ }
+
+ @Override
+ public List getManagedClassNames() {
+ return managedClassNames;
+ }
+
+ @Override
+ public boolean excludeUnlistedClasses() {
+ return false;
+ }
+
+ @Override
+ public SharedCacheMode getSharedCacheMode() {
+ return SharedCacheMode.UNSPECIFIED;
+ }
+
+ @Override
+ public ValidationMode getValidationMode() {
+ return ValidationMode.AUTO;
+ }
+
+ public Properties getProperties() {
+ return properties;
+ }
+
+ @Override
+ public String getPersistenceXMLSchemaVersion() {
+ return JPA_VERSION;
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+
+ @Override
+ public void addTransformer(ClassTransformer transformer) {
+ transformers.add(transformer);
+ }
+
+ @Override
+ public ClassLoader getNewTempClassLoader() {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/config/JpaEntityManagerFactory.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/config/JpaEntityManagerFactory.java
new file mode 100644
index 0000000000..bc1932af6f
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/config/JpaEntityManagerFactory.java
@@ -0,0 +1,69 @@
+package com.baeldung.hibernate.jpabootstrap.config;
+
+import com.mysql.cj.jdbc.MysqlDataSource;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.stream.Collectors;
+import javax.persistence.EntityManager;
+import javax.sql.DataSource;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.spi.PersistenceUnitInfo;
+import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
+import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
+
+public class JpaEntityManagerFactory {
+
+ private final String DB_URL = "jdbc:mysql://databaseurl";
+ private final String DB_USER_NAME = "username";
+ private final String DB_PASSWORD = "password";
+ private final Class[] entityClasses;
+
+ public JpaEntityManagerFactory(Class[] entityClasses) {
+ this.entityClasses = entityClasses;
+ }
+
+ public EntityManager getEntityManager() {
+ return getEntityManagerFactory().createEntityManager();
+ }
+
+ protected EntityManagerFactory getEntityManagerFactory() {
+ PersistenceUnitInfo persistenceUnitInfo = getPersistenceUnitInfo(getClass().getSimpleName());
+ Map configuration = new HashMap<>();
+ return new EntityManagerFactoryBuilderImpl(new PersistenceUnitInfoDescriptor(persistenceUnitInfo), configuration)
+ .build();
+ }
+
+ protected HibernatePersistenceUnitInfo getPersistenceUnitInfo(String name) {
+ return new HibernatePersistenceUnitInfo(name, getEntityClassNames(), getProperties());
+ }
+
+ protected List getEntityClassNames() {
+ return Arrays.asList(getEntities())
+ .stream()
+ .map(Class::getName)
+ .collect(Collectors.toList());
+ }
+
+ protected Properties getProperties() {
+ Properties properties = new Properties();
+ properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
+ properties.put("hibernate.id.new_generator_mappings", false);
+ properties.put("hibernate.connection.datasource", getMysqlDataSource());
+ return properties;
+ }
+
+ protected Class[] getEntities() {
+ return entityClasses;
+ }
+
+ protected DataSource getMysqlDataSource() {
+ MysqlDataSource mysqlDataSource = new MysqlDataSource();
+ mysqlDataSource.setURL(DB_URL);
+ mysqlDataSource.setUser(DB_USER_NAME);
+ mysqlDataSource.setPassword(DB_PASSWORD);
+ return mysqlDataSource;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/entities/User.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/entities/User.java
new file mode 100644
index 0000000000..86ca1dfa19
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpabootstrap/entities/User.java
@@ -0,0 +1,45 @@
+package com.baeldung.hibernate.jpabootstrap.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "users")
+public class User {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long id;
+ private String name;
+ private String email;
+
+ public User(){}
+
+ public User(String name, String email) {
+ this.name = name;
+ this.email = email;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpacriteriabuilder/service/EmployeeSearchService.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpacriteriabuilder/service/EmployeeSearchService.java
new file mode 100644
index 0000000000..b7d1a537f0
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpacriteriabuilder/service/EmployeeSearchService.java
@@ -0,0 +1,15 @@
+package com.baeldung.hibernate.jpacriteriabuilder.service;
+
+import java.util.List;
+
+import com.baeldung.hibernate.entities.DeptEmployee;
+
+public interface EmployeeSearchService {
+
+ List filterbyTitleUsingCriteriaBuilder(List titles);
+
+ List filterbyTitleUsingExpression(List titles);
+
+ List searchByDepartmentQuery(String query);
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpacriteriabuilder/service/EmployeeSearchServiceImpl.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpacriteriabuilder/service/EmployeeSearchServiceImpl.java
new file mode 100644
index 0000000000..e79168a451
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/jpacriteriabuilder/service/EmployeeSearchServiceImpl.java
@@ -0,0 +1,77 @@
+package com.baeldung.hibernate.jpacriteriabuilder.service;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaBuilder.In;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
+import javax.persistence.criteria.Subquery;
+
+import com.baeldung.hibernate.entities.Department;
+import com.baeldung.hibernate.entities.DeptEmployee;
+
+public class EmployeeSearchServiceImpl implements EmployeeSearchService {
+
+ private EntityManager entityManager;
+ private CriteriaBuilder criteriaBuilder;
+
+ public EmployeeSearchServiceImpl(EntityManager entityManager) {
+ this.entityManager = entityManager;
+ this.criteriaBuilder = entityManager.getCriteriaBuilder();
+
+ }
+
+ @Override
+ public List filterbyTitleUsingCriteriaBuilder(List titles) {
+ CriteriaQuery criteriaQuery = createCriteriaQuery(DeptEmployee.class);
+ Root root = criteriaQuery.from(DeptEmployee.class);
+ In inClause = criteriaBuilder.in(root.get("title"));
+ for (String title : titles) {
+ inClause.value(title);
+ }
+ criteriaQuery.select(root)
+ .where(inClause);
+ TypedQuery query = entityManager.createQuery(criteriaQuery);
+ return query.getResultList();
+ }
+
+ @Override
+ public List filterbyTitleUsingExpression(List titles) {
+ CriteriaQuery criteriaQuery = createCriteriaQuery(DeptEmployee.class);
+ Root root = criteriaQuery.from(DeptEmployee.class);
+ criteriaQuery.select(root)
+ .where(root.get("title")
+ .in(titles));
+ TypedQuery query = entityManager.createQuery(criteriaQuery);
+ return query.getResultList();
+ }
+
+ @Override
+ public List searchByDepartmentQuery(String searchKey) {
+ CriteriaQuery criteriaQuery = createCriteriaQuery(DeptEmployee.class);
+ Root emp = criteriaQuery.from(DeptEmployee.class);
+
+ Subquery subquery = criteriaQuery.subquery(Department.class);
+ Root dept = subquery.from(Department.class);
+ subquery.select(dept)
+ .distinct(true)
+ .where(criteriaBuilder.like(dept.get("name"), new StringBuffer("%").append(searchKey)
+ .append("%")
+ .toString()));
+
+ criteriaQuery.select(emp)
+ .where(criteriaBuilder.in(emp.get("department"))
+ .value(subquery));
+
+ TypedQuery query = entityManager.createQuery(criteriaQuery);
+ return query.getResultList();
+ }
+
+ private CriteriaQuery createCriteriaQuery(Class klass) {
+ return criteriaBuilder.createQuery(klass);
+ }
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/HibernateUtil.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/HibernateUtil.java
new file mode 100644
index 0000000000..18fa2a41db
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/HibernateUtil.java
@@ -0,0 +1,61 @@
+package com.baeldung.hibernate.onetoone;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.boot.Metadata;
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.service.ServiceRegistry;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+
+public class HibernateUtil {
+ private static SessionFactory sessionFactory;
+
+ private HibernateUtil() {
+ }
+
+ public static SessionFactory getSessionFactory(Strategy strategy) {
+ return buildSessionFactory(strategy);
+ }
+
+ private static SessionFactory buildSessionFactory(Strategy strategy) {
+ try {
+ ServiceRegistry serviceRegistry = configureServiceRegistry();
+
+ MetadataSources metadataSources = new MetadataSources(serviceRegistry);
+
+ for (Class> entityClass : strategy.getEntityClasses()) {
+ metadataSources.addAnnotatedClass(entityClass);
+ }
+
+ Metadata metadata = metadataSources.getMetadataBuilder()
+ .build();
+
+ return metadata.getSessionFactoryBuilder()
+ .build();
+ } catch (IOException ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+
+ private static ServiceRegistry configureServiceRegistry() throws IOException {
+ Properties properties = getProperties();
+ return new StandardServiceRegistryBuilder().applySettings(properties)
+ .build();
+ }
+
+ private static Properties getProperties() throws IOException {
+ Properties properties = new Properties();
+ URL propertiesURL = Thread.currentThread()
+ .getContextClassLoader()
+ .getResource("hibernate.properties");
+ try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) {
+ properties.load(inputStream);
+ }
+ return properties;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/Strategy.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/Strategy.java
new file mode 100644
index 0000000000..3180566ca5
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/Strategy.java
@@ -0,0 +1,25 @@
+package com.baeldung.hibernate.onetoone;
+
+
+import java.util.Arrays;
+import java.util.List;
+
+public enum Strategy {
+ //See that the classes belongs to different packages
+ FOREIGN_KEY(Arrays.asList(com.baeldung.hibernate.onetoone.foreignkeybased.User.class,
+ com.baeldung.hibernate.onetoone.foreignkeybased.Address.class)),
+ SHARED_PRIMARY_KEY(Arrays.asList(com.baeldung.hibernate.onetoone.sharedkeybased.User.class,
+ com.baeldung.hibernate.onetoone.sharedkeybased.Address.class)),
+ JOIN_TABLE_BASED(Arrays.asList(com.baeldung.hibernate.onetoone.jointablebased.Employee.class,
+ com.baeldung.hibernate.onetoone.jointablebased.WorkStation.class));
+
+ private List> entityClasses;
+
+ Strategy(List> entityClasses) {
+ this.entityClasses = entityClasses;
+ }
+
+ public List> getEntityClasses() {
+ return entityClasses;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/foreignkeybased/Address.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/foreignkeybased/Address.java
new file mode 100644
index 0000000000..e05eb46030
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/foreignkeybased/Address.java
@@ -0,0 +1,60 @@
+package com.baeldung.hibernate.onetoone.foreignkeybased;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "address")
+public class Address {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "street")
+ private String street;
+
+ @Column(name = "city")
+ private String city;
+
+ @OneToOne(mappedBy = "address")
+ private User user;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public void setUser(User user) {
+ this.user = user;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/foreignkeybased/User.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/foreignkeybased/User.java
new file mode 100644
index 0000000000..dda972f29c
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/foreignkeybased/User.java
@@ -0,0 +1,51 @@
+package com.baeldung.hibernate.onetoone.foreignkeybased;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "users")
+public class User {
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "username")
+ private String userName;
+
+ @OneToOne(cascade = CascadeType.ALL)
+ @JoinColumn(name = "address_id", referencedColumnName = "id")
+ private Address address;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/jointablebased/Employee.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/jointablebased/Employee.java
new file mode 100644
index 0000000000..a0bc101b9f
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/jointablebased/Employee.java
@@ -0,0 +1,53 @@
+package com.baeldung.hibernate.onetoone.jointablebased;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "employee")
+public class Employee {
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "ename")
+ private String name;
+
+ @OneToOne(cascade = CascadeType.ALL)
+ @JoinTable(name = "emp_workstation", joinColumns = {@JoinColumn(name = "employee_id", referencedColumnName = "id")},
+ inverseJoinColumns = {@JoinColumn(name = "workstation_id", referencedColumnName = "id")})
+ private WorkStation workStation;
+
+ 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 WorkStation getWorkStation() {
+ return workStation;
+ }
+
+ public void setWorkStation(WorkStation workStation) {
+ this.workStation = workStation;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/jointablebased/WorkStation.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/jointablebased/WorkStation.java
new file mode 100644
index 0000000000..f530611f6e
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/jointablebased/WorkStation.java
@@ -0,0 +1,61 @@
+package com.baeldung.hibernate.onetoone.jointablebased;
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "workstation")
+public class WorkStation {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "workstation_number")
+ private Integer workstationNumber;
+
+ @Column(name = "floor")
+ private String floor;
+
+ @OneToOne(mappedBy = "workStation")
+ private Employee employee;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Integer getWorkstationNumber() {
+ return workstationNumber;
+ }
+
+ public void setWorkstationNumber(Integer workstationNumber) {
+ this.workstationNumber = workstationNumber;
+ }
+
+ public String getFloor() {
+ return floor;
+ }
+
+ public void setFloor(String floor) {
+ this.floor = floor;
+ }
+
+ public Employee getEmployee() {
+ return employee;
+ }
+
+ public void setEmployee(Employee employee) {
+ this.employee = employee;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/sharedkeybased/Address.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/sharedkeybased/Address.java
new file mode 100644
index 0000000000..927516f6bb
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/sharedkeybased/Address.java
@@ -0,0 +1,60 @@
+package com.baeldung.hibernate.onetoone.sharedkeybased;
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.MapsId;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "address")
+public class Address {
+
+ @Id
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "street")
+ private String street;
+
+ @Column(name = "city")
+ private String city;
+
+ @OneToOne
+ @MapsId
+ private User user;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public void setUser(User user) {
+ this.user = user;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/sharedkeybased/User.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/sharedkeybased/User.java
new file mode 100644
index 0000000000..fa00db1271
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/onetoone/sharedkeybased/User.java
@@ -0,0 +1,50 @@
+package com.baeldung.hibernate.onetoone.sharedkeybased;
+
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "users")
+public class User {
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "username")
+ private String userName;
+
+ @OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
+ private Address address;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/optimisticlocking/OptimisticLockingCourse.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/optimisticlocking/OptimisticLockingCourse.java
new file mode 100644
index 0000000000..1af3e3e21b
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/optimisticlocking/OptimisticLockingCourse.java
@@ -0,0 +1,48 @@
+package com.baeldung.hibernate.optimisticlocking;
+
+import javax.persistence.*;
+
+@Entity
+public class OptimisticLockingCourse {
+
+ @Id
+ private Long id;
+
+ private String name;
+
+ @ManyToOne
+ @JoinTable(name = "optimistic_student_course")
+ private OptimisticLockingStudent student;
+
+ public OptimisticLockingCourse(Long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public OptimisticLockingCourse() {
+ }
+
+ 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 OptimisticLockingStudent getStudent() {
+ return student;
+ }
+
+ public void setStudent(OptimisticLockingStudent student) {
+ this.student = student;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/optimisticlocking/OptimisticLockingStudent.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/optimisticlocking/OptimisticLockingStudent.java
new file mode 100644
index 0000000000..b79212ae8d
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/optimisticlocking/OptimisticLockingStudent.java
@@ -0,0 +1,70 @@
+package com.baeldung.hibernate.optimisticlocking;
+
+import javax.persistence.*;
+import java.util.List;
+
+@Entity
+public class OptimisticLockingStudent {
+
+ @Id
+ private Long id;
+
+ private String name;
+
+ private String lastName;
+ @Version
+ private Integer version;
+
+ @OneToMany(mappedBy = "student")
+ private List courses;
+
+ public OptimisticLockingStudent(Long id, String name, String lastName, List courses) {
+ this.id = id;
+ this.name = name;
+ this.lastName = lastName;
+ this.courses = courses;
+ }
+
+ public OptimisticLockingStudent() {
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Integer getVersion() {
+ return version;
+ }
+
+ public void setVersion(Integer version) {
+ this.version = version;
+ }
+
+ 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 getCourses() {
+ return courses;
+ }
+
+ public void setCourses(List courses) {
+ this.courses = courses;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/Address.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/Address.java
new file mode 100644
index 0000000000..c889cb6127
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/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/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/Customer.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/Customer.java
new file mode 100644
index 0000000000..cb73cbc958
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/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/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/Individual.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/Individual.java
new file mode 100644
index 0000000000..e491c09eb5
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/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/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingCourse.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingCourse.java
new file mode 100644
index 0000000000..aea7d5fc87
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/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/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingEmployee.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingEmployee.java
new file mode 100644
index 0000000000..a1328cbdad
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/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/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingStudent.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockingStudent.java
new file mode 100644
index 0000000000..e6c5f476b4
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/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/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Movie.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Movie.java
new file mode 100644
index 0000000000..5fae7f6a97
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Movie.java
@@ -0,0 +1,52 @@
+package com.baeldung.hibernate.pojo;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "MOVIE")
+public class Movie {
+
+ @Id
+ private Long id;
+
+ private String movieName;
+
+ private Integer releaseYear;
+
+ private String language;
+
+ public String getMovieName() {
+ return movieName;
+ }
+
+ public void setMovieName(String movieName) {
+ this.movieName = movieName;
+ }
+
+ public Integer getReleaseYear() {
+ return releaseYear;
+ }
+
+ public void setReleaseYear(Integer releaseYear) {
+ this.releaseYear = releaseYear;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Person.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Person.java
new file mode 100644
index 0000000000..390a5954ed
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Person.java
@@ -0,0 +1,32 @@
+package com.baeldung.hibernate.pojo;
+
+import javax.persistence.Convert;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+import com.baeldung.hibernate.converters.PersonNameConverter;
+
+@Entity(name = "PersonTable")
+public class Person {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @Convert(converter = PersonNameConverter.class)
+ private PersonName personName;
+
+ public PersonName getPersonName() {
+ return personName;
+ }
+
+ public void setPersonName(PersonName personName) {
+ this.personName = personName;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/PersonName.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/PersonName.java
new file mode 100644
index 0000000000..335fe73f75
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/PersonName.java
@@ -0,0 +1,29 @@
+package com.baeldung.hibernate.pojo;
+
+import java.io.Serializable;
+
+public class PersonName implements Serializable {
+
+ private static final long serialVersionUID = 7883094644631050150L;
+
+ private String name;
+
+ private String surname;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getSurname() {
+ return surname;
+ }
+
+ public void setSurname(String surname) {
+ this.surname = surname;
+ }
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Post.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Post.java
new file mode 100644
index 0000000000..25e51e35d0
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Post.java
@@ -0,0 +1,59 @@
+package com.baeldung.hibernate.pojo;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "posts")
+public class Post {
+
+ @Id
+ @GeneratedValue
+ private int id;
+
+ private String title;
+
+ private String body;
+
+ public Post() { }
+
+ public Post(String title, String body) {
+ this.title = title;
+ this.body = body;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public void setBody(String body) {
+ this.body = body;
+ }
+
+ @Override
+ public String toString() {
+ return "Post{" +
+ "id=" + id +
+ ", title='" + title + '\'' +
+ ", body='" + body + '\'' +
+ '}';
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Student.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Student.java
new file mode 100644
index 0000000000..9b26c117eb
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/pojo/Student.java
@@ -0,0 +1,51 @@
+package com.baeldung.hibernate.pojo;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Student {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE)
+ private long studentId;
+
+ private String name;
+
+ private int age;
+
+ public Student() {
+ }
+
+ public Student(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public long getStudentId() {
+ return studentId;
+ }
+
+ public void setStudentId(long studentId) {
+ this.studentId = studentId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/transaction/PostService.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/transaction/PostService.java
new file mode 100644
index 0000000000..5a4eb20079
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/hibernate/transaction/PostService.java
@@ -0,0 +1,29 @@
+package com.baeldung.hibernate.transaction;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.query.Query;
+
+public class PostService {
+
+
+ private Session session;
+
+ public PostService(Session session) {
+ this.session = session;
+ }
+
+
+ public void updatePost(String title, String body, int id) {
+ Transaction txn = session.beginTransaction();
+ Query updateQuery = session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3");
+ updateQuery.setParameter(1, title);
+ updateQuery.setParameter(2, body);
+ updateQuery.setParameter(3, id);
+ updateQuery.executeUpdate();
+ txn.commit();
+ }
+
+
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/PersistenceContextDemoApplication.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/PersistenceContextDemoApplication.java
new file mode 100644
index 0000000000..17fa582e10
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/PersistenceContextDemoApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.persistencecontext;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@ComponentScan(basePackages="com.baeldung.persistencecontext")
+public class PersistenceContextDemoApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(PersistenceContextDemoApplication.class, args);
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/entity/User.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/entity/User.java
new file mode 100644
index 0000000000..7252ac46f5
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/entity/User.java
@@ -0,0 +1,36 @@
+package com.baeldung.persistencecontext.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+@Entity
+public class User {
+
+ @Id
+ private Long id;
+ private String name;
+ private String role;
+
+ public User() {
+
+ }
+
+ public User(Long id, String name, String role) {
+ this.id = id;
+ this.name = name;
+ this.role = role;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/service/ExtendedPersistenceContextUserService.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/service/ExtendedPersistenceContextUserService.java
new file mode 100644
index 0000000000..ef25aac69f
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/service/ExtendedPersistenceContextUserService.java
@@ -0,0 +1,33 @@
+package com.baeldung.persistencecontext.service;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.PersistenceContextType;
+import javax.transaction.Transactional;
+
+import org.springframework.stereotype.Component;
+
+import com.baeldung.persistencecontext.entity.User;
+
+@Component
+public class ExtendedPersistenceContextUserService {
+
+ @PersistenceContext(type = PersistenceContextType.EXTENDED)
+ private EntityManager entityManager;
+
+ @Transactional
+ public User insertWithTransaction(User user) {
+ entityManager.persist(user);
+ return user;
+ }
+
+ public User insertWithoutTransaction(User user) {
+ entityManager.persist(user);
+ return user;
+ }
+
+ public User find(long id) {
+ User user = entityManager.find(User.class, id);
+ return user;
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/service/TransctionPersistenceContextUserService.java b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/service/TransctionPersistenceContextUserService.java
new file mode 100644
index 0000000000..481defcf08
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/java/com/baeldung/persistencecontext/service/TransctionPersistenceContextUserService.java
@@ -0,0 +1,32 @@
+package com.baeldung.persistencecontext.service;
+
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.transaction.Transactional;
+
+import org.springframework.stereotype.Component;
+
+import com.baeldung.persistencecontext.entity.User;
+
+@Component
+public class TransctionPersistenceContextUserService {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Transactional
+ public User insertWithTransaction(User user) {
+ entityManager.persist(user);
+ return user;
+ }
+
+ public User insertWithoutTransaction(User user) {
+ entityManager.persist(user);
+ return user;
+ }
+
+ public User find(long id) {
+ return entityManager.find(User.class, id);
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/main/resources/META-INF/persistence.xml b/persistence-modules/hibernate5-jpa/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 0000000000..4dfade1af3
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,19 @@
+
+
+
+ Hibernate EntityManager Demo
+ com.baeldung.hibernate.pojo.Movie
+ true
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-jpa/src/main/resources/init_database.sql b/persistence-modules/hibernate5-jpa/src/main/resources/init_database.sql
new file mode 100644
index 0000000000..b2848aa256
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/resources/init_database.sql
@@ -0,0 +1,10 @@
+CREATE ALIAS UPDATE_EMPLOYEE_DESIGNATION AS $$
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.SQLException;
+@CODE
+void updateEmployeeDesignation(final Connection conn, final String employeeNumber, final String title) throws SQLException {
+ CallableStatement updateStatement = conn.prepareCall("update deptemployee set title = '" + title + "' where employeeNumber = '" + employeeNumber + "'");
+ updateStatement.execute();
+}
+$$;
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-jpa/src/main/resources/logback.xml b/persistence-modules/hibernate5-jpa/src/main/resources/logback.xml
new file mode 100644
index 0000000000..7d900d8ea8
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterUnitTest.java b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterUnitTest.java
new file mode 100644
index 0000000000..3cd4761a7b
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterUnitTest.java
@@ -0,0 +1,200 @@
+package com.baeldung.hibernate.converter;
+
+import java.io.IOException;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.baeldung.hibernate.HibernateUtil;
+import com.baeldung.hibernate.pojo.Person;
+import com.baeldung.hibernate.pojo.PersonName;
+
+import static org.junit.Assert.assertEquals;
+
+public class PersonNameConverterUnitTest {
+
+ private Session session;
+ private Transaction transaction;
+
+ @Before
+ public void setUp() throws IOException {
+ session = HibernateUtil.getSessionFactory()
+ .openSession();
+ transaction = session.beginTransaction();
+
+ session.createNativeQuery("delete from personTable")
+ .executeUpdate();
+
+ transaction.commit();
+ transaction = session.beginTransaction();
+ }
+
+ @After
+ public void tearDown() {
+ transaction.rollback();
+ session.close();
+ }
+
+ @Test
+ public void givenPersonName_WhenSaving_ThenNameAndSurnameConcat() {
+ final String name = "name";
+ final String surname = "surname";
+
+ PersonName personName = new PersonName();
+ personName.setName(name);
+ personName.setSurname(surname);
+
+ Person person = new Person();
+ person.setPersonName(personName);
+
+ Long id = (Long) session.save(person);
+
+ session.flush();
+ session.clear();
+
+ String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id")
+ .setParameter("id", id)
+ .getSingleResult();
+
+ assertEquals(surname + ", " + name, dbPersonName);
+
+ Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class)
+ .setParameter("id", id)
+ .getSingleResult();
+
+ assertEquals(dbPerson.getPersonName()
+ .getName(), name);
+ assertEquals(dbPerson.getPersonName()
+ .getSurname(), surname);
+ }
+
+ @Test
+ public void givenPersonNameNull_WhenSaving_ThenNullStored() {
+ final String name = null;
+ final String surname = null;
+
+ PersonName personName = new PersonName();
+ personName.setName(name);
+ personName.setSurname(surname);
+
+ Person person = new Person();
+ person.setPersonName(personName);
+
+ Long id = (Long) session.save(person);
+
+ session.flush();
+ session.clear();
+
+ String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id")
+ .setParameter("id", id)
+ .getSingleResult();
+
+ assertEquals("", dbPersonName);
+
+ Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class)
+ .setParameter("id", id)
+ .getSingleResult();
+
+ assertEquals(dbPerson.getPersonName(), null);
+ }
+
+ @Test
+ public void givenPersonNameWithoutName_WhenSaving_ThenNotNameStored() {
+ final String name = null;
+ final String surname = "surname";
+
+ PersonName personName = new PersonName();
+ personName.setName(name);
+ personName.setSurname(surname);
+
+ Person person = new Person();
+ person.setPersonName(personName);
+
+ Long id = (Long) session.save(person);
+
+ session.flush();
+ session.clear();
+
+ String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id")
+ .setParameter("id", id)
+ .getSingleResult();
+
+ assertEquals("surname, ", dbPersonName);
+
+ Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class)
+ .setParameter("id", id)
+ .getSingleResult();
+
+ assertEquals(dbPerson.getPersonName()
+ .getName(), name);
+ assertEquals(dbPerson.getPersonName()
+ .getSurname(), surname);
+ }
+
+ @Test
+ public void givenPersonNameWithoutSurName_WhenSaving_ThenNotSurNameStored() {
+ final String name = "name";
+ final String surname = null;
+
+ PersonName personName = new PersonName();
+ personName.setName(name);
+ personName.setSurname(surname);
+
+ Person person = new Person();
+ person.setPersonName(personName);
+
+ Long id = (Long) session.save(person);
+
+ session.flush();
+ session.clear();
+
+ String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id")
+ .setParameter("id", id)
+ .getSingleResult();
+
+ assertEquals("name", dbPersonName);
+
+ Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class)
+ .setParameter("id", id)
+ .getSingleResult();
+
+ assertEquals(dbPerson.getPersonName()
+ .getName(), name);
+ assertEquals(dbPerson.getPersonName()
+ .getSurname(), surname);
+ }
+
+ @Test
+ public void givenPersonNameEmptyFields_WhenSaving_ThenFielsNotStored() {
+ final String name = "";
+ final String surname = "";
+
+ PersonName personName = new PersonName();
+ personName.setName(name);
+ personName.setSurname(surname);
+
+ Person person = new Person();
+ person.setPersonName(personName);
+
+ Long id = (Long) session.save(person);
+
+ session.flush();
+ session.clear();
+
+ String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id")
+ .setParameter("id", id)
+ .getSingleResult();
+
+ assertEquals("", dbPersonName);
+
+ Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class)
+ .setParameter("id", id)
+ .getSingleResult();
+
+ assertEquals(dbPerson.getPersonName(), null);
+ }
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/jpacriteriabuilder/EmployeeSearchServiceIntegrationTest.java b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/jpacriteriabuilder/EmployeeSearchServiceIntegrationTest.java
new file mode 100644
index 0000000000..2b12734a10
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/jpacriteriabuilder/EmployeeSearchServiceIntegrationTest.java
@@ -0,0 +1,121 @@
+package com.baeldung.hibernate.jpacriteriabuilder;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.persistence.EntityManager;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.baeldung.hibernate.HibernateUtil;
+import com.baeldung.hibernate.entities.Department;
+import com.baeldung.hibernate.entities.DeptEmployee;
+import com.baeldung.hibernate.jpacriteriabuilder.service.EmployeeSearchService;
+import com.baeldung.hibernate.jpacriteriabuilder.service.EmployeeSearchServiceImpl;
+
+public class EmployeeSearchServiceIntegrationTest {
+
+ private EntityManager entityManager;
+ private EmployeeSearchService searchService;
+ private Session session;
+
+ @Before
+ public final void setup() throws HibernateException, IOException {
+ session = HibernateUtil.getSessionFactory()
+ .openSession();
+ entityManager = session.getEntityManagerFactory()
+ .createEntityManager();
+ searchService = new EmployeeSearchServiceImpl(entityManager);
+
+ entityManager.getTransaction()
+ .begin();
+ Department department = new Department("Pre Sales");
+ DeptEmployee employee = new DeptEmployee("John Smith", "001", "Manager", department);
+ entityManager.persist(department);
+ entityManager.persist(employee);
+ employee = new DeptEmployee("Ian Evans", "002", "Associate", department);
+ entityManager.persist(department);
+ entityManager.persist(employee);
+ department = new Department("Copporate Sales");
+ employee = new DeptEmployee("Robert Carter", "003", "Manager", department);
+ entityManager.persist(department);
+ entityManager.persist(employee);
+ employee = new DeptEmployee("John Carter", "004", "Senior Manager", department);
+ entityManager.persist(employee);
+ employee = new DeptEmployee("David Guetta", "009", "Associate", department);
+ entityManager.persist(department);
+ entityManager.persist(employee);
+ department = new Department("Post Sales");
+ employee = new DeptEmployee("Robert Jonas", "005", "Director", department);
+ entityManager.persist(department);
+ entityManager.persist(employee);
+ employee = new DeptEmployee("John Ferros", "006", "Junior Associate", department);
+ entityManager.persist(department);
+ entityManager.persist(employee);
+ department = new Department("Client Support");
+ employee = new DeptEmployee("Robert Mcclements", "007", "Director", department);
+ entityManager.persist(department);
+ entityManager.persist(employee);
+ employee = new DeptEmployee("Peter Parker", "008", "Manager", department);
+ entityManager.persist(department);
+ entityManager.persist(employee);
+
+ }
+
+ @After
+ public final void teardown() {
+ entityManager.getTransaction()
+ .rollback();
+ entityManager.close();
+ }
+
+ @Test
+ public final void givenCriteriaQuery_whenSearchedUsingCriteriaBuilderWithListofAuthors_thenResultIsFilteredByAuthorNames() {
+ List titles = new ArrayList() {
+ {
+ add("Manager");
+ add("Senior Manager");
+ add("Director");
+ }
+ };
+ List result = searchService.filterbyTitleUsingCriteriaBuilder(titles);
+ assertEquals("Number of Employees does not match with expected.", 6, result.size());
+ assertThat(result.stream()
+ .map(DeptEmployee::getTitle)
+ .distinct()
+ .collect(Collectors.toList()), containsInAnyOrder(titles.toArray()));
+ }
+
+ @Test
+ public final void givenCriteriaQuery_whenSearchedUsingExpressionWithListofAuthors_thenResultIsFilteredByAuthorNames() {
+ List titles = new ArrayList() {
+ {
+ add("Manager");
+ add("Senior Manager");
+ add("Director");
+ }
+ };
+ List result = searchService.filterbyTitleUsingExpression(titles);
+ assertEquals("Number of Employees does not match with expected.", 6, result.size());
+ assertThat(result.stream()
+ .map(DeptEmployee::getTitle)
+ .distinct()
+ .collect(Collectors.toList()), containsInAnyOrder(titles.toArray()));
+ }
+
+ @Test
+ public final void givenCriteriaQuery_whenSearchedDepartmentLike_thenResultIsFilteredByDepartment() {
+ List result = searchService.searchByDepartmentQuery("Sales");
+ assertEquals("Number of Employees does not match with expected.", 7, result.size());
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/onetoone/HibernateOneToOneAnnotationFKBasedIntegrationTest.java b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/onetoone/HibernateOneToOneAnnotationFKBasedIntegrationTest.java
new file mode 100644
index 0000000000..475c93f6ff
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/onetoone/HibernateOneToOneAnnotationFKBasedIntegrationTest.java
@@ -0,0 +1,80 @@
+package com.baeldung.hibernate.onetoone;
+
+import com.baeldung.hibernate.onetoone.foreignkeybased.Address;
+import com.baeldung.hibernate.onetoone.foreignkeybased.User;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class HibernateOneToOneAnnotationFKBasedIntegrationTest {
+
+ private static SessionFactory sessionFactory;
+
+ private Session session;
+
+ @BeforeClass
+ public static void beforeTests() {
+ sessionFactory = HibernateUtil.getSessionFactory(Strategy.FOREIGN_KEY);
+ }
+
+ @Before
+ public void setUp() {
+ session = sessionFactory.openSession();
+ session.beginTransaction();
+ }
+
+ @Test
+ public void givenData_whenInsert_thenCreates1to1relationship() {
+ User user = new User();
+ user.setUserName("alice@baeldung.com");
+
+ Address address = new Address();
+ address.setStreet("FK Street");
+ address.setCity("FK City");
+
+ address.setUser(user);
+ user.setAddress(address);
+
+ //Address entry will automatically be created by hibernate, since cascade type is specified as ALL
+ session.persist(user);
+ session.getTransaction().commit();
+
+ assert1to1InsertedData();
+ }
+
+ private void assert1to1InsertedData() {
+ @SuppressWarnings("unchecked")
+ List userList = session.createQuery("FROM User").list();
+
+ assertNotNull(userList);
+ assertEquals(1, userList.size());
+
+ User user = userList.get(0);
+ assertEquals("alice@baeldung.com", user.getUserName());
+
+ Address address = user.getAddress();
+ assertNotNull(address);
+ assertEquals("FK Street", address.getStreet());
+ assertEquals("FK City", address.getCity());
+
+ }
+
+ @After
+ public void tearDown() {
+ session.close();
+ }
+
+ @AfterClass
+ public static void afterTests() {
+ sessionFactory.close();
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/onetoone/HibernateOneToOneAnnotationJTBasedIntegrationTest.java b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/onetoone/HibernateOneToOneAnnotationJTBasedIntegrationTest.java
new file mode 100644
index 0000000000..df4cd4d137
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/onetoone/HibernateOneToOneAnnotationJTBasedIntegrationTest.java
@@ -0,0 +1,80 @@
+package com.baeldung.hibernate.onetoone;
+
+import com.baeldung.hibernate.onetoone.jointablebased.Employee;
+import com.baeldung.hibernate.onetoone.jointablebased.WorkStation;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class HibernateOneToOneAnnotationJTBasedIntegrationTest {
+
+ private static SessionFactory sessionFactory;
+
+ private Session session;
+
+ @BeforeClass
+ public static void beforeTests() {
+ sessionFactory = HibernateUtil.getSessionFactory(Strategy.JOIN_TABLE_BASED);
+ }
+
+ @Before
+ public void setUp() {
+ session = sessionFactory.openSession();
+ session.beginTransaction();
+ }
+
+ @Test
+ public void givenData_whenInsert_thenCreates1to1relationship() {
+ Employee employee = new Employee();
+ employee.setName("bob@baeldung.com");
+
+ WorkStation workStation = new WorkStation();
+ workStation.setWorkstationNumber(626);
+ workStation.setFloor("Sixth Floor");
+
+
+ employee.setWorkStation(workStation);
+ workStation.setEmployee(employee);
+
+ session.persist(employee);
+ session.getTransaction().commit();
+
+ assert1to1InsertedData();
+ }
+
+ private void assert1to1InsertedData() {
+ @SuppressWarnings("unchecked")
+ List employeeList = session.createQuery("FROM Employee").list();
+ assertNotNull(employeeList);
+ assertEquals(1, employeeList.size());
+
+ Employee employee = employeeList.get(0);
+ assertEquals("bob@baeldung.com", employee.getName());
+
+ WorkStation workStation = employee.getWorkStation();
+
+ assertNotNull(workStation);
+ assertEquals((long) 626, (long) workStation.getWorkstationNumber());
+ assertEquals("Sixth Floor", workStation.getFloor());
+
+ }
+
+ @After
+ public void tearDown() {
+ session.close();
+ }
+
+ @AfterClass
+ public static void afterTests() {
+ sessionFactory.close();
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/onetoone/HibernateOneToOneAnnotationSPKBasedIntegrationTest.java b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/onetoone/HibernateOneToOneAnnotationSPKBasedIntegrationTest.java
new file mode 100644
index 0000000000..7931a8e3fe
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/onetoone/HibernateOneToOneAnnotationSPKBasedIntegrationTest.java
@@ -0,0 +1,79 @@
+package com.baeldung.hibernate.onetoone;
+
+import com.baeldung.hibernate.onetoone.sharedkeybased.Address;
+import com.baeldung.hibernate.onetoone.sharedkeybased.User;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class HibernateOneToOneAnnotationSPKBasedIntegrationTest {
+
+ private static SessionFactory sessionFactory;
+
+ private Session session;
+
+ @BeforeClass
+ public static void beforeTests() {
+ sessionFactory = HibernateUtil.getSessionFactory(Strategy.SHARED_PRIMARY_KEY);
+ }
+
+ @Before
+ public void setUp() {
+ session = sessionFactory.openSession();
+ session.beginTransaction();
+ }
+
+ @Test
+ public void givenData_whenInsert_thenCreates1to1relationship() {
+ User user = new User();
+ user.setUserName("alice@baeldung.com");
+
+ Address address = new Address();
+ address.setStreet("SPK Street");
+ address.setCity("SPK City");
+
+ address.setUser(user);
+ user.setAddress(address);
+
+ //Address entry will automatically be created by hibernate, since cascade type is specified as ALL
+ session.persist(user);
+ session.getTransaction().commit();
+
+ assert1to1InsertedData();
+ }
+
+
+ private void assert1to1InsertedData() {
+ @SuppressWarnings("unchecked")
+ List userList = session.createQuery("FROM User").list();
+ assertNotNull(userList);
+ assertEquals(1, userList.size());
+
+ User user = userList.get(0);
+ assertEquals("alice@baeldung.com", user.getUserName());
+
+ Address address = user.getAddress();
+ assertNotNull(address);
+ assertEquals("SPK Street", address.getStreet());
+ assertEquals("SPK City", address.getCity());
+ }
+
+ @After
+ public void tearDown() {
+ session.close();
+ }
+
+ @AfterClass
+ public static void afterTests() {
+ sessionFactory.close();
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/optimisticlocking/OptimisticLockingIntegrationTest.java b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/optimisticlocking/OptimisticLockingIntegrationTest.java
new file mode 100644
index 0000000000..37c490f297
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/optimisticlocking/OptimisticLockingIntegrationTest.java
@@ -0,0 +1,146 @@
+package com.baeldung.hibernate.optimisticlocking;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import javax.persistence.EntityManager;
+import javax.persistence.LockModeType;
+import javax.persistence.OptimisticLockException;
+
+import org.hibernate.SessionFactory;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.baeldung.hibernate.HibernateUtil;
+
+public class OptimisticLockingIntegrationTest {
+
+ private static SessionFactory sessionFactory;
+
+ @Before
+ public void setUp() throws IOException {
+ EntityManager entityManager = getEntityManagerWithOpenTransaction();
+ OptimisticLockingCourse course = new OptimisticLockingCourse(1L, "MATH");
+ OptimisticLockingStudent student = new OptimisticLockingStudent(1L, "John", "Doe", Arrays.asList(course));
+ course.setStudent(student);
+ entityManager.persist(course);
+ entityManager.persist(student);
+ entityManager.getTransaction()
+ .commit();
+ entityManager.close();
+ }
+
+ @After
+ public void clean() throws IOException {
+ EntityManager entityManager = getEntityManagerWithOpenTransaction();
+ OptimisticLockingCourse course = entityManager.find(OptimisticLockingCourse.class, 1L);
+ OptimisticLockingStudent student = entityManager.find(OptimisticLockingStudent.class, 1L);
+ entityManager.remove(course);
+ entityManager.remove(student);
+ entityManager.getTransaction()
+ .commit();
+ entityManager.close();
+ }
+
+ @Test(expected = OptimisticLockException.class)
+ public void givenVersionedEntities_whenConcurrentUpdate_thenOptimisticLockException() throws IOException {
+ EntityManager em = getEntityManagerWithOpenTransaction();
+ OptimisticLockingStudent student = em.find(OptimisticLockingStudent.class, 1L);
+
+ EntityManager em2 = getEntityManagerWithOpenTransaction();
+ OptimisticLockingStudent student2 = em2.find(OptimisticLockingStudent.class, 1L);
+ student2.setName("RICHARD");
+ em2.persist(student2);
+ em2.getTransaction()
+ .commit();
+ em2.close();
+
+ student.setName("JOHN");
+ em.persist(student);
+ em.getTransaction()
+ .commit();
+ em.close();
+ }
+
+ @Test(expected = OptimisticLockException.class)
+ public void givenVersionedEntitiesWithLockByFindMethod_whenConcurrentUpdate_thenOptimisticLockException() throws IOException {
+ EntityManager em = getEntityManagerWithOpenTransaction();
+ OptimisticLockingStudent student = em.find(OptimisticLockingStudent.class, 1L, LockModeType.OPTIMISTIC);
+
+ EntityManager em2 = getEntityManagerWithOpenTransaction();
+ OptimisticLockingStudent student2 = em2.find(OptimisticLockingStudent.class, 1L, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
+ student2.setName("RICHARD");
+ em2.persist(student2);
+ em2.getTransaction()
+ .commit();
+ em2.close();
+
+ student.setName("JOHN");
+ em.persist(student);
+ em.getTransaction()
+ .commit();
+ em.close();
+ }
+
+ @Test(expected = OptimisticLockException.class)
+ public void givenVersionedEntitiesWithLockByRefreshMethod_whenConcurrentUpdate_thenOptimisticLockException() throws IOException {
+ EntityManager em = getEntityManagerWithOpenTransaction();
+ OptimisticLockingStudent student = em.find(OptimisticLockingStudent.class, 1L);
+ em.refresh(student, LockModeType.OPTIMISTIC);
+
+ EntityManager em2 = getEntityManagerWithOpenTransaction();
+ OptimisticLockingStudent student2 = em2.find(OptimisticLockingStudent.class, 1L);
+ em.refresh(student, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
+ student2.setName("RICHARD");
+ em2.persist(student2);
+ em2.getTransaction()
+ .commit();
+ em2.close();
+
+ student.setName("JOHN");
+ em.persist(student);
+ em.getTransaction()
+ .commit();
+ em.close();
+ }
+
+ @Test(expected = OptimisticLockException.class)
+ public void givenVersionedEntitiesWithLockByLockMethod_whenConcurrentUpdate_thenOptimisticLockException() throws IOException {
+ EntityManager em = getEntityManagerWithOpenTransaction();
+ OptimisticLockingStudent student = em.find(OptimisticLockingStudent.class, 1L);
+ em.lock(student, LockModeType.OPTIMISTIC);
+
+ EntityManager em2 = getEntityManagerWithOpenTransaction();
+ OptimisticLockingStudent student2 = em2.find(OptimisticLockingStudent.class, 1L);
+ em.lock(student, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
+ student2.setName("RICHARD");
+ em2.persist(student2);
+ em2.getTransaction()
+ .commit();
+ em2.close();
+
+ student.setName("JOHN");
+ em.persist(student);
+ em.getTransaction()
+ .commit();
+ em.close();
+ }
+
+ protected static EntityManager getEntityManagerWithOpenTransaction() throws IOException {
+ String propertyFileName = "hibernate-pessimistic-locking.properties";
+ if (sessionFactory == null) {
+ sessionFactory = HibernateUtil.getSessionFactory(propertyFileName);
+ }
+ EntityManager entityManager = sessionFactory.openSession();
+ entityManager.getTransaction().begin();
+
+ return entityManager;
+ }
+
+ @AfterClass
+ public static void afterTests() {
+ sessionFactory.close();
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/pessimisticlocking/BasicPessimisticLockingIntegrationTest.java b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/pessimisticlocking/BasicPessimisticLockingIntegrationTest.java
new file mode 100644
index 0000000000..4b9c7720fd
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/pessimisticlocking/BasicPessimisticLockingIntegrationTest.java
@@ -0,0 +1,162 @@
+package com.baeldung.hibernate.pessimisticlocking;
+
+import com.baeldung.hibernate.HibernateUtil;
+import com.vividsolutions.jts.util.Assert;
+
+import org.hibernate.SessionFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.persistence.*;
+import java.io.IOException;
+import java.util.Arrays;
+
+public class BasicPessimisticLockingIntegrationTest {
+
+ private static SessionFactory sessionFactory;
+
+ @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";
+ if (sessionFactory == null) {
+ sessionFactory = HibernateUtil.getSessionFactory(propertyFileName);
+ }
+ EntityManager entityManager = sessionFactory.openSession();
+ entityManager.getTransaction().begin();
+
+ return entityManager;
+ }
+
+ @AfterClass
+ public static void afterTests() {
+ sessionFactory.close();
+ }
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockScopesIntegrationTest.java b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockScopesIntegrationTest.java
new file mode 100644
index 0000000000..81cb7d95f8
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/pessimisticlocking/PessimisticLockScopesIntegrationTest.java
@@ -0,0 +1,125 @@
+package com.baeldung.hibernate.pessimisticlocking;
+
+import com.baeldung.hibernate.HibernateUtil;
+
+import org.hibernate.SessionFactory;
+import org.junit.AfterClass;
+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 {
+
+ private static SessionFactory sessionFactory;
+
+ @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";
+ if (sessionFactory == null) {
+ sessionFactory = HibernateUtil.getSessionFactory(propertyFileName);
+ }
+ EntityManager entityManager = sessionFactory.openSession();
+ entityManager.getTransaction().begin();
+
+ return entityManager;
+ }
+
+ @AfterClass
+ public static void afterTests() {
+ sessionFactory.close();
+ }
+}
diff --git a/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/transaction/TransactionIntegrationTest.java b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/transaction/TransactionIntegrationTest.java
new file mode 100644
index 0000000000..246a7d59f9
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/hibernate/transaction/TransactionIntegrationTest.java
@@ -0,0 +1,57 @@
+package com.baeldung.hibernate.transaction;
+
+import com.baeldung.hibernate.HibernateUtil;
+import com.baeldung.hibernate.pojo.Post;
+import com.baeldung.hibernate.transaction.PostService;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+
+public class TransactionIntegrationTest {
+
+ private static PostService postService;
+ private static Session session;
+ private static Logger logger = LoggerFactory.getLogger(TransactionIntegrationTest.class);
+
+ @BeforeClass
+ public static void init() throws IOException {
+ Properties properties = new Properties();
+ properties.setProperty("hibernate.connection.driver_class", "org.h2.Driver");
+ properties.setProperty("hibernate.connection.url", "jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1");
+ properties.setProperty("hibernate.connection.username", "sa");
+ properties.setProperty("hibernate.show_sql", "true");
+ properties.setProperty("jdbc.password", "");
+ properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
+ properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
+ SessionFactory sessionFactory = HibernateUtil.getSessionFactoryByProperties(properties);
+ session = sessionFactory.openSession();
+ postService = new PostService(session);
+ }
+
+ @Test
+ public void givenTitleAndBody_whenRepositoryUpdatePost_thenUpdatePost() {
+
+ Post post = new Post("This is a title", "This is a sample post");
+ session.persist(post);
+
+ String title = "[UPDATE] Java HowTos";
+ String body = "This is an updated posts on Java how-tos";
+ postService.updatePost(title, body, post.getId());
+
+ session.refresh(post);
+
+ assertEquals(post.getTitle(), title);
+ assertEquals(post.getBody(), body);
+ }
+
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/persistencecontext/PersistenceContextIntegrationTest.java b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/persistencecontext/PersistenceContextIntegrationTest.java
new file mode 100644
index 0000000000..b299dd5834
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/java/com/baeldung/persistencecontext/PersistenceContextIntegrationTest.java
@@ -0,0 +1,90 @@
+package com.baeldung.persistencecontext;
+
+import com.baeldung.persistencecontext.entity.User;
+import com.baeldung.persistencecontext.service.ExtendedPersistenceContextUserService;
+import com.baeldung.persistencecontext.service.TransctionPersistenceContextUserService;
+
+import javax.persistence.EntityExistsException;
+import javax.persistence.TransactionRequiredException;
+
+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 static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = com.baeldung.persistencecontext.PersistenceContextDemoApplication.class)
+public class PersistenceContextIntegrationTest {
+
+ @Autowired
+ private TransctionPersistenceContextUserService transctionPersistenceContext;
+ @Autowired
+ private ExtendedPersistenceContextUserService extendedPersistenceContext;
+
+ @Test
+ public void testThatWhenUserSavedWithTransctionPersistenceContextThenUserShouldGetSavedInDB() {
+ User user = new User(121L, "Devender", "admin");
+ transctionPersistenceContext.insertWithTransaction(user);
+
+ User userFromTransctionPersistenceContext = transctionPersistenceContext.find(user.getId());
+ assertNotNull(userFromTransctionPersistenceContext);
+
+ User userFromExtendedPersistenceContext = extendedPersistenceContext.find(user.getId());
+ assertNotNull(userFromExtendedPersistenceContext);
+ }
+
+ @Test(expected = TransactionRequiredException.class)
+ public void testThatUserSaveWithoutTransactionThrowException() {
+ User user = new User(122L, "Devender", "admin");
+ transctionPersistenceContext.insertWithoutTransaction(user);
+ }
+
+ @Test
+ public void testThatWhenUserSavedWithExtendedPersistenceContextWithoutTransactionThenUserShouldGetCached() {
+ User user = new User(123L, "Devender", "admin");
+ extendedPersistenceContext.insertWithoutTransaction(user);
+
+ User userFromExtendedPersistenceContext = extendedPersistenceContext.find(user.getId());
+ assertNotNull(userFromExtendedPersistenceContext);
+
+ User userFromTransctionPersistenceContext = transctionPersistenceContext.find(user.getId());
+ assertNull(userFromTransctionPersistenceContext);
+ }
+
+ @Test(expected = EntityExistsException.class)
+ public void testThatPersistUserWithSameIdentifierThrowException() {
+ User user1 = new User(126L, "Devender", "admin");
+ User user2 = new User(126L, "Devender", "admin");
+ extendedPersistenceContext.insertWithoutTransaction(user1);
+ extendedPersistenceContext.insertWithoutTransaction(user2);
+ }
+
+ @Test
+ public void testThatWhenUserSavedWithExtendedPersistenceContextWithTransactionThenUserShouldSaveEntityIntoDB() {
+ User user = new User(127L, "Devender", "admin");
+ extendedPersistenceContext.insertWithTransaction(user);
+
+ User userFromDB = transctionPersistenceContext.find(user.getId());
+ assertNotNull(userFromDB);
+ }
+
+ @Test
+ public void testThatWhenUserSavedWithExtendedPersistenceContextWithTransactionThenUserShouldFlushCachedEntityIntoDB() {
+ User user1 = new User(124L, "Devender", "admin");
+ extendedPersistenceContext.insertWithoutTransaction(user1);
+
+ User user2 = new User(125L, "Devender", "admin");
+ extendedPersistenceContext.insertWithTransaction(user2);
+
+ User user1FromTransctionPersistenceContext = transctionPersistenceContext.find(user1.getId());
+ assertNotNull(user1FromTransctionPersistenceContext);
+
+ User user2FromTransctionPersistenceContext = transctionPersistenceContext.find(user2.getId());
+ assertNotNull(user2FromTransctionPersistenceContext);
+ }
+
+}
diff --git a/persistence-modules/hibernate5-jpa/src/test/resources/hibernate-namedquery.properties b/persistence-modules/hibernate5-jpa/src/test/resources/hibernate-namedquery.properties
new file mode 100644
index 0000000000..457f965347
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/resources/hibernate-namedquery.properties
@@ -0,0 +1,9 @@
+hibernate.connection.driver_class=org.h2.Driver
+hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'src/main/resources/init_database.sql'
+hibernate.connection.username=sa
+hibernate.connection.autocommit=true
+jdbc.password=
+
+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/hibernate5-jpa/src/test/resources/hibernate-pessimistic-locking.properties b/persistence-modules/hibernate5-jpa/src/test/resources/hibernate-pessimistic-locking.properties
new file mode 100644
index 0000000000..4f1ff5e93a
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/resources/hibernate-pessimistic-locking.properties
@@ -0,0 +1,8 @@
+hibernate.connection.driver_class=org.h2.Driver
+hibernate.connection.url=jdbc:h2:mem:mydb3;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/hibernate5-jpa/src/test/resources/hibernate.properties b/persistence-modules/hibernate5-jpa/src/test/resources/hibernate.properties
new file mode 100644
index 0000000000..c14782ce0f
--- /dev/null
+++ b/persistence-modules/hibernate5-jpa/src/test/resources/hibernate.properties
@@ -0,0 +1,14 @@
+hibernate.connection.driver_class=org.h2.Driver
+hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1
+hibernate.connection.username=sa
+hibernate.connection.autocommit=true
+jdbc.password=
+
+hibernate.dialect=org.hibernate.dialect.H2Dialect
+hibernate.show_sql=true
+hibernate.hbm2ddl.auto=create-drop
+
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.acquire_increment=5
+hibernate.c3p0.timeout=1800
diff --git a/persistence-modules/hibernate5-jpa/src/test/resources/profile.png b/persistence-modules/hibernate5-jpa/src/test/resources/profile.png
new file mode 100644
index 0000000000..1cd4e978b9
Binary files /dev/null and b/persistence-modules/hibernate5-jpa/src/test/resources/profile.png differ