diff --git a/persistence-modules/hibernate5-enterprise/README.md b/persistence-modules/hibernate5-enterprise/README.md
new file mode 100644
index 0000000000..994d8f062a
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/README.md
@@ -0,0 +1,13 @@
+## Hibernate 5
+
+This module contains articles about Hibernate 5.
+
+### Relevant articles:
+
+- [Introduction to Hibernate Spatial](http://www.baeldung.com/hibernate-spatial)
+- [A Guide to Multitenancy in Hibernate 5](http://www.baeldung.com/hibernate-5-multitenancy)
+- [Hibernate Aggregate Functions](https://www.baeldung.com/hibernate-aggregate-functions)
+- [Common Hibernate Exceptions](https://www.baeldung.com/hibernate-exceptions)
+- [Hibernate Error “Not all named parameters have been set”](https://www.baeldung.com/hibernate-error-named-parameters-not-set)
+- [FetchMode in Hibernate](https://www.baeldung.com/hibernate-fetchmode)
+- [Various Logging Levels in Hibernate](https://www.baeldung.com/hibernate-logging-levels)
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-enterprise/pom.xml b/persistence-modules/hibernate5-enterprise/pom.xml
new file mode 100644
index 0000000000..f12bb7e081
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/pom.xml
@@ -0,0 +1,76 @@
+
+
+ 4.0.0
+ hibernate5-enterprise
+ 0.0.1-SNAPSHOT
+ hibernate5-enterprise
+
+
+ com.baeldung
+ persistence-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ org.hibernate
+ hibernate-core
+ ${hibernate.version}
+
+
+ org.assertj
+ assertj-core
+ ${assertj-core.version}
+ test
+
+
+ com.h2database
+ h2
+ ${h2.version}
+
+
+ org.hibernate
+ hibernate-spatial
+ ${hibernate.version}
+
+
+ org.opengeo
+ geodb
+ ${geodb.version}
+
+
+ mysql
+ mysql-connector-java
+ ${mysql.version}
+
+
+ ch.vorburger.mariaDB4j
+ mariaDB4j
+ ${mariaDB4j.version}
+
+
+ org.hibernate
+ hibernate-testing
+ ${hibernate.version}
+
+
+
+
+
+ geodb-repo
+ GeoDB repository
+ http://repo.boundlessgeo.com/main/
+
+
+
+
+ 5.3.7.Final
+ 6.0.6
+ 2.2.3
+ 3.8.0
+ 0.9
+
+
+
diff --git a/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/HibernateUtil.java b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/HibernateUtil.java
new file mode 100644
index 0000000000..ddeb1c42ea
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/HibernateUtil.java
@@ -0,0 +1,72 @@
+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.pojo.PointEntity;
+import com.baeldung.hibernate.pojo.PolygonEntity;
+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(Student.class);
+ metadataSources.addAnnotatedClass(PointEntity.class);
+ metadataSources.addAnnotatedClass(PolygonEntity.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-enterprise/src/main/java/com/baeldung/hibernate/UnsupportedTenancyException.java b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/UnsupportedTenancyException.java
new file mode 100644
index 0000000000..99d9505ea3
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/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-enterprise/src/main/java/com/baeldung/hibernate/exception/EntityWithNoId.java b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/exception/EntityWithNoId.java
new file mode 100644
index 0000000000..989fa1281a
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/exception/EntityWithNoId.java
@@ -0,0 +1,16 @@
+package com.baeldung.hibernate.exception;
+
+import javax.persistence.Entity;
+
+@Entity
+public class EntityWithNoId {
+ private int id;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/exception/HibernateUtil.java b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/exception/HibernateUtil.java
new file mode 100644
index 0000000000..ae5174ac9c
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/exception/HibernateUtil.java
@@ -0,0 +1,63 @@
+package com.baeldung.hibernate.exception;
+
+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;
+
+public class HibernateUtil {
+ private static SessionFactory sessionFactory;
+ 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;
+ if (sessionFactory == null) {
+ ServiceRegistry serviceRegistry = configureServiceRegistry();
+ sessionFactory = makeSessionFactory(serviceRegistry);
+ }
+ return sessionFactory;
+ }
+
+ private static SessionFactory makeSessionFactory(
+ ServiceRegistry serviceRegistry) {
+ MetadataSources metadataSources = new MetadataSources(serviceRegistry);
+ metadataSources.addAnnotatedClass(Product.class);
+ Metadata metadata = metadataSources.getMetadataBuilder()
+ .build();
+ return metadata.getSessionFactoryBuilder()
+ .build();
+
+ }
+
+ 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(StringUtils.defaultString(PROPERTY_FILE_NAME,
+ "hibernate-exception.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-enterprise/src/main/java/com/baeldung/hibernate/exception/Product.java b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/exception/Product.java
new file mode 100644
index 0000000000..031fa38de0
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/exception/Product.java
@@ -0,0 +1,40 @@
+package com.baeldung.hibernate.exception;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+@Entity
+public class Product {
+
+ private int id;
+
+ private String name;
+ private String description;
+
+ @Id
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ @Column(nullable=false)
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/logging/Employee.java b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/logging/Employee.java
new file mode 100644
index 0000000000..9dcf4058a7
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/logging/Employee.java
@@ -0,0 +1,59 @@
+package com.baeldung.hibernate.logging;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Employee {
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE)
+ private long id;
+
+ private String employeeNumber;
+
+ private String title;
+
+ private String name;
+
+ public Employee() {
+ }
+
+ public Employee(String name, String employeeNumber) {
+ this.name = name;
+ this.employeeNumber = employeeNumber;
+ }
+
+ 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 String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/pojo/PointEntity.java b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/pojo/PointEntity.java
new file mode 100644
index 0000000000..736abde866
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/pojo/PointEntity.java
@@ -0,0 +1,43 @@
+package com.baeldung.hibernate.pojo;
+
+import com.vividsolutions.jts.geom.Point;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+public class PointEntity {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @Column(columnDefinition="BINARY(2048)")
+ private Point point;
+
+ public PointEntity() {
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Point getPoint() {
+ return point;
+ }
+
+ public void setPoint(Point point) {
+ this.point = point;
+ }
+
+ @Override
+ public String toString() {
+ return "PointEntity{" + "id=" + id + ", point=" + point + '}';
+ }
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/pojo/PolygonEntity.java b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/pojo/PolygonEntity.java
new file mode 100644
index 0000000000..69208c8cd4
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/pojo/PolygonEntity.java
@@ -0,0 +1,38 @@
+package com.baeldung.hibernate.pojo;
+
+import com.vividsolutions.jts.geom.Polygon;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+public class PolygonEntity {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private Polygon polygon;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Polygon getPolygon() {
+ return polygon;
+ }
+
+ public void setPolygon(Polygon polygon) {
+ this.polygon = polygon;
+ }
+
+ @Override
+ public String toString() {
+ return "PolygonEntity{" + "id=" + id + ", polygon=" + polygon + '}';
+ }
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/pojo/Student.java b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernate/pojo/Student.java
new file mode 100644
index 0000000000..9b26c117eb
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/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-enterprise/src/main/java/com/baeldung/hibernateparameters/Event.java b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernateparameters/Event.java
new file mode 100644
index 0000000000..7912659a09
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/java/com/baeldung/hibernateparameters/Event.java
@@ -0,0 +1,30 @@
+package com.baeldung.hibernateparameters;
+
+public class Event {
+ private Long id;
+
+ private String title;
+
+ public Event() {
+ }
+
+ public Event(String title) {
+ this.title = title;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ private void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-enterprise/src/main/resources/META-INF/persistence.xml b/persistence-modules/hibernate5-enterprise/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 0000000000..474eeb7a44
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,18 @@
+
+
+
+ Hibernate EntityManager Demo
+ true
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-enterprise/src/main/resources/com/baeldung/hibernateparameters/Event.hbm.xml b/persistence-modules/hibernate5-enterprise/src/main/resources/com/baeldung/hibernateparameters/Event.hbm.xml
new file mode 100644
index 0000000000..c485080879
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/resources/com/baeldung/hibernateparameters/Event.hbm.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/persistence-modules/hibernate5-enterprise/src/main/resources/hibernate-logging.cfg.xml b/persistence-modules/hibernate5-enterprise/src/main/resources/hibernate-logging.cfg.xml
new file mode 100644
index 0000000000..52ef1ee685
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/resources/hibernate-logging.cfg.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ org.h2.Driver
+ jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1
+ sa
+
+
+ 1
+
+ org.hibernate.dialect.H2Dialect
+
+ org.hibernate.cache.internal.NoCacheProvider
+
+ true
+
+ create
+
+
+
+
+
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-enterprise/src/main/resources/hibernate.cfg.xml b/persistence-modules/hibernate5-enterprise/src/main/resources/hibernate.cfg.xml
new file mode 100644
index 0000000000..be564aaf5a
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/main/resources/hibernate.cfg.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+ org.h2.Driver
+ jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1
+ sa
+
+
+ 1
+
+ org.hibernate.dialect.H2Dialect
+
+ org.hibernate.cache.internal.NoCacheProvider
+
+ true
+
+ create
+
+
+
+
+
+
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-enterprise/src/main/resources/init_database.sql b/persistence-modules/hibernate5-enterprise/src/main/resources/init_database.sql
new file mode 100644
index 0000000000..b2848aa256
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/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-enterprise/src/main/resources/logback.xml b/persistence-modules/hibernate5-enterprise/src/main/resources/logback.xml
new file mode 100644
index 0000000000..7d900d8ea8
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/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-enterprise/src/test/java/com/baeldung/hibernate/HibernateSpatialIntegrationTest.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/HibernateSpatialIntegrationTest.java
new file mode 100644
index 0000000000..74f752ab8c
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/HibernateSpatialIntegrationTest.java
@@ -0,0 +1,161 @@
+package com.baeldung.hibernate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+
+import javax.persistence.Query;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.baeldung.hibernate.pojo.PointEntity;
+import com.baeldung.hibernate.pojo.PolygonEntity;
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.Polygon;
+import com.vividsolutions.jts.io.ParseException;
+import com.vividsolutions.jts.io.WKTReader;
+import com.vividsolutions.jts.util.GeometricShapeFactory;
+
+import geodb.GeoDB;
+
+public class HibernateSpatialIntegrationTest {
+
+ private Session session;
+ private Transaction transaction;
+
+ @Before
+ public void setUp() throws IOException {
+ session = HibernateUtil.getSessionFactory("hibernate-spatial.properties")
+ .openSession();
+ transaction = session.beginTransaction();
+ session.doWork(conn -> { GeoDB.InitGeoDB(conn); });
+ }
+
+ @After
+ public void tearDown() {
+ transaction.rollback();
+ session.close();
+ }
+
+ @Test
+ public void shouldConvertWktToGeometry() throws ParseException {
+ Geometry geometry = wktToGeometry("POINT (2 5)");
+ assertEquals("Point", geometry.getGeometryType());
+ assertTrue(geometry instanceof Point);
+ }
+
+ @Test
+ public void shouldInsertAndSelectPoints() throws ParseException {
+ PointEntity entity = new PointEntity();
+ entity.setPoint((Point) wktToGeometry("POINT (1 1)"));
+
+ session.persist(entity);
+ PointEntity fromDb = session.find(PointEntity.class, entity.getId());
+ assertEquals("POINT (1 1)", fromDb.getPoint().toString());
+ }
+
+ @Test
+ public void shouldSelectDisjointPoints() throws ParseException {
+ insertPoint("POINT (1 2)");
+ insertPoint("POINT (3 4)");
+ insertPoint("POINT (5 6)");
+
+ Point point = (Point) wktToGeometry("POINT (3 4)");
+ Query query = session.createQuery("select p from PointEntity p "
+ + "where disjoint(p.point, :point) = true", PointEntity.class);
+ query.setParameter("point", point);
+ assertEquals("POINT (1 2)", ((PointEntity) query.getResultList().get(0)).getPoint().toString());
+ assertEquals("POINT (5 6)", ((PointEntity) query.getResultList().get(1)).getPoint().toString());
+ }
+
+ @Test
+ public void shouldSelectAllPointsWithinPolygon() throws ParseException {
+ insertPoint("POINT (1 1)");
+ insertPoint("POINT (1 2)");
+ insertPoint("POINT (3 4)");
+ insertPoint("POINT (5 6)");
+
+ Query query = session.createQuery("select p from PointEntity p where within(p.point, :area) = true",
+ PointEntity.class);
+ query.setParameter("area", wktToGeometry("POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))"));
+ assertThat(query.getResultList().stream().map(p -> ((PointEntity) p).getPoint().toString()))
+ .containsOnly("POINT (1 1)", "POINT (1 2)", "POINT (3 4)");
+ }
+
+ @Test
+ public void shouldSelectAllPointsWithinRadius() throws ParseException {
+ insertPoint("POINT (1 1)");
+ insertPoint("POINT (1 2)");
+ insertPoint("POINT (3 4)");
+ insertPoint("POINT (5 6)");
+
+ Query query = session.createQuery("select p from PointEntity p where within(p.point, :circle) = true",
+ PointEntity.class);
+ query.setParameter("circle", createCircle(0.0, 0.0, 5));
+
+ assertThat(query.getResultList().stream().map(p -> ((PointEntity) p).getPoint().toString()))
+ .containsOnly("POINT (1 1)", "POINT (1 2)");
+ }
+
+ @Test
+ public void shouldSelectAdjacentPolygons() throws ParseException {
+ insertPolygon("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))");
+ insertPolygon("POLYGON ((3 0, 3 5, 8 5, 8 0, 3 0))");
+ insertPolygon("POLYGON ((2 2, 3 1, 2 5, 4 3, 3 3, 2 2))");
+
+ Query query = session.createQuery("select p from PolygonEntity p where touches(p.polygon, :polygon) = true",
+ PolygonEntity.class);
+ query.setParameter("polygon", wktToGeometry("POLYGON ((5 5, 5 10, 10 10, 10 5, 5 5))"));
+ assertThat(query.getResultList().stream().map(p -> ((PolygonEntity) p).getPolygon().toString()))
+ .containsOnly("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))", "POLYGON ((3 0, 3 5, 8 5, 8 0, 3 0))");
+ }
+
+ private void insertPoint(String point) throws ParseException {
+ PointEntity entity = new PointEntity();
+ entity.setPoint((Point) wktToGeometry(point));
+ session.persist(entity);
+ }
+
+ private void insertPolygon(String polygon) throws ParseException {
+ PolygonEntity entity = new PolygonEntity();
+ entity.setPolygon((Polygon) wktToGeometry(polygon));
+ session.persist(entity);
+ }
+
+ private Geometry wktToGeometry(String wellKnownText) throws ParseException {
+ WKTReader fromText = new WKTReader();
+ Geometry geom = null;
+ geom = fromText.read(wellKnownText);
+ return geom;
+ }
+
+ private static Geometry createCircle(double x, double y, double radius) {
+ GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
+ shapeFactory.setNumPoints(32);
+ shapeFactory.setCentre(new Coordinate(x, y));
+ shapeFactory.setSize(radius * 2);
+ return shapeFactory.createCircle();
+ }
+
+ public static Properties getProperties(String propertyFile) throws IOException {
+ Properties properties = new Properties();
+ URL propertiesURL = Thread.currentThread()
+ .getContextClassLoader()
+ .getResource(propertyFile);
+ try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) {
+ properties.load(inputStream);
+ }
+ return properties;
+ }
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/aggregatefunctions/AggregateFunctionsIntegrationTest.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/aggregatefunctions/AggregateFunctionsIntegrationTest.java
new file mode 100644
index 0000000000..0b2bdf7ead
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/aggregatefunctions/AggregateFunctionsIntegrationTest.java
@@ -0,0 +1,87 @@
+package com.baeldung.hibernate.aggregatefunctions;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.baeldung.hibernate.HibernateUtil;
+import com.baeldung.hibernate.pojo.Student;
+
+public class AggregateFunctionsIntegrationTest {
+
+ private static Session session;
+ private static Transaction transaction;
+
+ @BeforeClass
+ public static final void setup() throws HibernateException, IOException {
+ session = HibernateUtil.getSessionFactory()
+ .openSession();
+ transaction = session.beginTransaction();
+
+ Student jonas = new Student("Jonas", 22);
+ session.save(jonas);
+
+ Student sally = new Student("Sally", 20);
+ session.save(sally);
+
+ Student simon = new Student("Simon", 25);
+ session.save(simon);
+
+ Student raven = new Student("Raven", 21);
+ session.save(raven);
+
+ Student sam = new Student("Sam", 23);
+ session.save(sam);
+
+ }
+
+ @AfterClass
+ public static final void teardown() {
+ if (session != null) {
+ transaction.rollback();
+ session.close();
+ }
+ }
+
+ @Test
+ public void whenMaxAge_ThenReturnValue() {
+ int maxAge = (int) session.createQuery("SELECT MAX(age) from Student")
+ .getSingleResult();
+ assertThat(maxAge).isEqualTo(25);
+ }
+
+ @Test
+ public void whenMinAge_ThenReturnValue() {
+ int minAge = (int) session.createQuery("SELECT MIN(age) from Student")
+ .getSingleResult();
+ assertThat(minAge).isEqualTo(20);
+ }
+
+ @Test
+ public void whenAverageAge_ThenReturnValue() {
+ Double avgAge = (Double) session.createQuery("SELECT AVG(age) from Student")
+ .getSingleResult();
+ assertThat(avgAge).isEqualTo(22.2);
+ }
+
+ @Test
+ public void whenCountAll_ThenReturnValue() {
+ Long totalStudents = (Long) session.createQuery("SELECT COUNT(*) from Student")
+ .getSingleResult();
+ assertThat(totalStudents).isEqualTo(5);
+ }
+
+ @Test
+ public void whenSumOfAllAges_ThenReturnValue() {
+ Long sumOfAllAges = (Long) session.createQuery("SELECT SUM(age) from Student")
+ .getSingleResult();
+ assertThat(sumOfAllAges).isEqualTo(111);
+ }
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/exception/HibernateExceptionUnitTest.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/exception/HibernateExceptionUnitTest.java
new file mode 100644
index 0000000000..3581c81daa
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/exception/HibernateExceptionUnitTest.java
@@ -0,0 +1,425 @@
+package com.baeldung.hibernate.exception;
+
+import static org.hamcrest.CoreMatchers.isA;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.persistence.OptimisticLockException;
+import javax.persistence.PersistenceException;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.NonUniqueObjectException;
+import org.hibernate.PropertyValueException;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.StaleObjectStateException;
+import org.hibernate.StaleStateException;
+import org.hibernate.Transaction;
+import org.hibernate.TransactionException;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.exception.ConstraintViolationException;
+import org.hibernate.exception.DataException;
+import org.hibernate.exception.SQLGrammarException;
+import org.hibernate.query.NativeQuery;
+import org.hibernate.tool.schema.spi.CommandAcceptanceException;
+import org.hibernate.tool.schema.spi.SchemaManagementException;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HibernateExceptionUnitTest {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(HibernateExceptionUnitTest.class);
+ private SessionFactory sessionFactory;
+
+ @Before
+ public void setUp() throws IOException {
+ sessionFactory = HibernateUtil.getSessionFactory();
+ }
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ private Configuration getConfiguration() {
+ Configuration cfg = new Configuration();
+ cfg.setProperty(AvailableSettings.DIALECT,
+ "org.hibernate.dialect.H2Dialect");
+ cfg.setProperty(AvailableSettings.HBM2DDL_AUTO, "none");
+ cfg.setProperty(AvailableSettings.DRIVER, "org.h2.Driver");
+ cfg.setProperty(AvailableSettings.URL,
+ "jdbc:h2:mem:myexceptiondb2;DB_CLOSE_DELAY=-1");
+ cfg.setProperty(AvailableSettings.USER, "sa");
+ cfg.setProperty(AvailableSettings.PASS, "");
+ return cfg;
+ }
+
+ @Test
+ public void whenQueryExecutedWithUnmappedEntity_thenMappingException() {
+ thrown.expectCause(isA(MappingException.class));
+ thrown.expectMessage("Unknown entity: java.lang.String");
+
+ Session session = sessionFactory.openSession();
+ NativeQuery query = session
+ .createNativeQuery("select name from PRODUCT", String.class);
+ query.getResultList();
+ }
+
+ @Test
+ @SuppressWarnings("rawtypes")
+ public void whenQueryExecuted_thenOK() {
+ Session session = sessionFactory.openSession();
+ NativeQuery query = session
+ .createNativeQuery("select name from PRODUCT");
+ List results = query.getResultList();
+ assertNotNull(results);
+ }
+
+ @Test
+ public void givenEntityWithoutId_whenSessionFactoryCreated_thenAnnotationException() {
+ thrown.expect(AnnotationException.class);
+ thrown.expectMessage("No identifier specified for entity");
+
+ Configuration cfg = getConfiguration();
+ cfg.addAnnotatedClass(EntityWithNoId.class);
+ cfg.buildSessionFactory();
+ }
+
+ @Test
+ public void givenMissingTable_whenSchemaValidated_thenSchemaManagementException() {
+ thrown.expect(SchemaManagementException.class);
+ thrown.expectMessage("Schema-validation: missing table");
+
+ Configuration cfg = getConfiguration();
+ cfg.setProperty(AvailableSettings.HBM2DDL_AUTO, "validate");
+ cfg.addAnnotatedClass(Product.class);
+ cfg.buildSessionFactory();
+ }
+
+ @Test
+ public void whenWrongDialectSpecified_thenCommandAcceptanceException() {
+ thrown.expect(SchemaManagementException.class);
+ thrown.expectCause(isA(CommandAcceptanceException.class));
+ thrown.expectMessage("Halting on error : Error executing DDL");
+
+ Configuration cfg = getConfiguration();
+ cfg.setProperty(AvailableSettings.DIALECT,
+ "org.hibernate.dialect.MySQLDialect");
+ cfg.setProperty(AvailableSettings.HBM2DDL_AUTO, "update");
+
+ // This does not work due to hibernate bug
+ // cfg.setProperty(AvailableSettings.HBM2DDL_HALT_ON_ERROR,"true");
+ cfg.getProperties()
+ .put(AvailableSettings.HBM2DDL_HALT_ON_ERROR, true);
+
+ cfg.addAnnotatedClass(Product.class);
+ cfg.buildSessionFactory();
+ }
+
+ @Test
+ public void givenMissingTable_whenEntitySaved_thenSQLGrammarException() {
+ thrown.expect(isA(PersistenceException.class));
+ thrown.expectCause(isA(SQLGrammarException.class));
+ thrown
+ .expectMessage("SQLGrammarException: could not prepare statement");
+
+ Configuration cfg = getConfiguration();
+ cfg.addAnnotatedClass(Product.class);
+
+ SessionFactory sessionFactory = cfg.buildSessionFactory();
+ Session session = null;
+ Transaction transaction = null;
+ try {
+
+ session = sessionFactory.openSession();
+ transaction = session.beginTransaction();
+ Product product = new Product();
+ product.setId(1);
+ product.setName("Product 1");
+ session.save(product);
+ transaction.commit();
+ } catch (Exception e) {
+ rollbackTransactionQuietly(transaction);
+ throw (e);
+ } finally {
+ closeSessionQuietly(session);
+ closeSessionFactoryQuietly(sessionFactory);
+ }
+ }
+
+ @Test
+ public void givenMissingTable_whenQueryExecuted_thenSQLGrammarException() {
+ thrown.expect(isA(PersistenceException.class));
+ thrown.expectCause(isA(SQLGrammarException.class));
+ thrown
+ .expectMessage("SQLGrammarException: could not prepare statement");
+
+ Session session = sessionFactory.openSession();
+ NativeQuery query = session.createNativeQuery(
+ "select * from NON_EXISTING_TABLE", Product.class);
+ query.getResultList();
+ }
+
+ @Test
+ public void whenDuplicateIdSaved_thenConstraintViolationException() {
+ thrown.expect(isA(PersistenceException.class));
+ thrown.expectCause(isA(ConstraintViolationException.class));
+ thrown.expectMessage(
+ "ConstraintViolationException: could not execute statement");
+
+ Session session = null;
+ Transaction transaction = null;
+
+ for (int i = 1; i <= 2; i++) {
+ try {
+ session = sessionFactory.openSession();
+ transaction = session.beginTransaction();
+ Product product = new Product();
+ product.setId(1);
+ product.setName("Product " + i);
+ session.save(product);
+ transaction.commit();
+ } catch (Exception e) {
+ rollbackTransactionQuietly(transaction);
+ throw (e);
+ } finally {
+ closeSessionQuietly(session);
+ }
+ }
+ }
+
+ @Test
+ public void givenNotNullPropertyNotSet_whenEntityIdSaved_thenPropertyValueException() {
+ thrown.expect(isA(PropertyValueException.class));
+ thrown.expectMessage(
+ "not-null property references a null or transient value");
+
+ Session session = null;
+ Transaction transaction = null;
+
+ try {
+ session = sessionFactory.openSession();
+ transaction = session.beginTransaction();
+
+ Product product = new Product();
+ product.setId(1);
+ session.save(product);
+ transaction.commit();
+ } catch (Exception e) {
+ rollbackTransactionQuietly(transaction);
+ throw (e);
+ } finally {
+ closeSessionQuietly(session);
+ }
+
+ }
+
+ @Test
+ public void givenQueryWithDataTypeMismatch_WhenQueryExecuted_thenDataException() {
+ thrown.expectCause(isA(DataException.class));
+ thrown.expectMessage(
+ "org.hibernate.exception.DataException: could not prepare statement");
+
+ Session session = sessionFactory.openSession();
+ NativeQuery query = session.createNativeQuery(
+ "select * from PRODUCT where id='wrongTypeId'", Product.class);
+ query.getResultList();
+ }
+
+ @Test
+ public void givenSessionContainingAnId_whenIdAssociatedAgain_thenNonUniqueObjectException() {
+ thrown.expect(isA(NonUniqueObjectException.class));
+ thrown.expectMessage(
+ "A different object with the same identifier value was already associated with the session");
+
+ Session session = null;
+ Transaction transaction = null;
+
+ try {
+ session = sessionFactory.openSession();
+ transaction = session.beginTransaction();
+
+ Product product1 = new Product();
+ product1.setId(1);
+ product1.setName("Product 1");
+ session.save(product1);
+
+ Product product2 = new Product();
+ product2.setId(1);
+ product2.setName("Product 2");
+ session.save(product2);
+
+ transaction.commit();
+ } catch (Exception e) {
+ rollbackTransactionQuietly(transaction);
+ throw (e);
+ } finally {
+ closeSessionQuietly(session);
+ }
+ }
+
+ @Test
+ public void whenDeletingADeletedObject_thenOptimisticLockException() {
+ thrown.expect(isA(OptimisticLockException.class));
+ thrown.expectMessage(
+ "Batch update returned unexpected row count from update");
+ thrown.expectCause(isA(StaleStateException.class));
+
+ Session session = null;
+ Transaction transaction = null;
+
+ try {
+ session = sessionFactory.openSession();
+ transaction = session.beginTransaction();
+
+ Product product1 = new Product();
+ product1.setId(12);
+ product1.setName("Product 12");
+ session.save(product1);
+ transaction.commit();
+ session.close();
+
+ session = sessionFactory.openSession();
+ transaction = session.beginTransaction();
+ Product product2 = session.get(Product.class, 12);
+ session.createNativeQuery("delete from Product where id=12")
+ .executeUpdate();
+ // We need to refresh to fix the error.
+ // session.refresh(product2);
+ session.delete(product2);
+ transaction.commit();
+ } catch (Exception e) {
+ rollbackTransactionQuietly(transaction);
+ throw (e);
+ } finally {
+ closeSessionQuietly(session);
+ }
+ }
+
+ @Test
+ public void whenUpdatingNonExistingObject_thenStaleStateException() {
+ thrown.expect(isA(OptimisticLockException.class));
+ thrown
+ .expectMessage("Row was updated or deleted by another transaction");
+ thrown.expectCause(isA(StaleObjectStateException.class));
+
+ Session session = null;
+ Transaction transaction = null;
+
+ try {
+ session = sessionFactory.openSession();
+ transaction = session.beginTransaction();
+
+ Product product1 = new Product();
+ product1.setId(15);
+ product1.setName("Product1");
+ session.update(product1);
+ transaction.commit();
+ } catch (Exception e) {
+ rollbackTransactionQuietly(transaction);
+ throw (e);
+ } finally {
+ closeSessionQuietly(session);
+ }
+ }
+
+ @Test
+ public void givenTxnMarkedRollbackOnly_whenCommitted_thenTransactionException() {
+ thrown.expect(isA(TransactionException.class));
+
+ Session session = null;
+ Transaction transaction = null;
+ try {
+ session = sessionFactory.openSession();
+ transaction = session.beginTransaction();
+
+ Product product1 = new Product();
+ product1.setId(15);
+ product1.setName("Product1");
+ session.save(product1);
+ transaction.setRollbackOnly();
+
+ transaction.commit();
+ } catch (Exception e) {
+ rollbackTransactionQuietly(transaction);
+ throw (e);
+ } finally {
+ closeSessionQuietly(session);
+ }
+ }
+
+ private void rollbackTransactionQuietly(Transaction transaction) {
+ if (transaction != null && transaction.isActive()) {
+ try {
+ transaction.rollback();
+ } catch (Exception e) {
+ logger.error("Exception while rolling back transaction", e);
+ }
+ }
+ }
+
+ private void closeSessionQuietly(Session session) {
+ if (session != null) {
+ try {
+ session.close();
+ } catch (Exception e) {
+ logger.error("Exception while closing session", e);
+ }
+ }
+ }
+
+ private void closeSessionFactoryQuietly(SessionFactory sessionFactory) {
+ if (sessionFactory != null) {
+ try {
+ sessionFactory.close();
+ } catch (Exception e) {
+ logger.error("Exception while closing sessionFactory", e);
+ }
+ }
+ }
+
+ @Test
+ public void givenExistingEntity_whenIdUpdated_thenHibernateException() {
+ thrown.expect(isA(PersistenceException.class));
+ thrown.expectCause(isA(HibernateException.class));
+ thrown.expectMessage(
+ "identifier of an instance of com.baeldung.hibernate.exception.Product was altered");
+
+ Session session = null;
+ Transaction transaction = null;
+
+ try {
+ session = sessionFactory.openSession();
+ transaction = session.beginTransaction();
+
+ Product product1 = new Product();
+ product1.setId(222);
+ product1.setName("Product 222");
+ session.save(product1);
+ transaction.commit();
+ closeSessionQuietly(session);
+
+ session = sessionFactory.openSession();
+ transaction = session.beginTransaction();
+
+ Product product2 = session.get(Product.class, 222);
+ product2.setId(333);
+ session.save(product2);
+
+ transaction.commit();
+ } catch (Exception e) {
+ rollbackTransactionQuietly(transaction);
+ throw (e);
+ } finally {
+ closeSessionQuietly(session);
+ }
+ }
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/logging/HibernateLoggingIntegrationTest.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/logging/HibernateLoggingIntegrationTest.java
new file mode 100644
index 0000000000..f609c75834
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/logging/HibernateLoggingIntegrationTest.java
@@ -0,0 +1,50 @@
+package com.baeldung.hibernate.logging;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistry;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.query.Query;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.baeldung.hibernate.logging.Employee;
+
+public class HibernateLoggingIntegrationTest {
+
+ private SessionFactory sessionFactory;
+
+ @Before
+ public void setUp() throws IOException {
+ final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure("hibernate-logging.cfg.xml")
+ .build();
+ try {
+ sessionFactory = new MetadataSources(registry).buildMetadata()
+ .buildSessionFactory();
+ Session session = sessionFactory.openSession();
+ session.beginTransaction();
+ session.save(new Employee("John Smith", "001"));
+ session.getTransaction()
+ .commit();
+ session.close();
+ } catch (Exception e) {
+ fail(e);
+ StandardServiceRegistryBuilder.destroy(registry);
+ }
+ }
+
+ @Test
+ public void whenAllEmployeesAreSelected_ThenSuccess() {
+ Query query = sessionFactory.openSession().createQuery("from com.baeldung.hibernate.logging.Employee", Employee.class);
+ List deptEmployees = query.list();
+ Employee deptEmployee = deptEmployees.get(0);
+ assertEquals("John Smith", deptEmployee.getName());
+ }
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/Car.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/Car.java
new file mode 100644
index 0000000000..1b6cee7e67
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/Car.java
@@ -0,0 +1,26 @@
+package com.baeldung.hibernate.multitenancy;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity(name = "Car")
+@Table(name = "Car")
+public class Car implements Serializable {
+
+ private static final long serialVersionUID = 1015320564683423342L;
+
+ private String brand;
+
+ @Id
+ public String getBrand() {
+ return brand;
+ }
+
+ public void setBrand(String brand) {
+ this.brand = brand;
+ }
+
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/MultitenancyIntegrationTest.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/MultitenancyIntegrationTest.java
new file mode 100644
index 0000000000..fdc3f9fa81
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/MultitenancyIntegrationTest.java
@@ -0,0 +1,104 @@
+package com.baeldung.hibernate.multitenancy;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
+import org.hibernate.service.ServiceRegistry;
+import org.junit.Before;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import com.baeldung.hibernate.multitenancy.database.TenantIdNames;
+
+public abstract class MultitenancyIntegrationTest {
+
+ public abstract String getPropertyFile();
+
+ @Mock
+ private CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
+
+ private SessionFactory sessionFactory;
+
+ @Before
+ public void setup() throws IOException {
+ MockitoAnnotations.initMocks(this);
+
+ Mockito.when(currentTenantIdentifierResolver.validateExistingCurrentSessions())
+ .thenReturn(false);
+
+ Properties properties = getHibernateProperties();
+ properties.put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver);
+
+ sessionFactory = buildSessionFactory(properties);
+
+ initTenant(TenantIdNames.MYDB1);
+ initTenant(TenantIdNames.MYDB2);
+ }
+
+ protected void initTenant(String tenantId) {
+ whenCurrentTenantIs(tenantId);
+ createCarTable();
+ }
+
+ protected void whenCurrentTenantIs(String tenantId) {
+ Mockito.when(currentTenantIdentifierResolver.resolveCurrentTenantIdentifier())
+ .thenReturn(tenantId);
+ }
+
+ protected void whenAddCar(String brand) {
+ Session session = sessionFactory.openSession();
+ Transaction tx = session.beginTransaction();
+ Car car = new Car();
+ car.setBrand(brand);
+ session.save(car);
+ tx.commit();
+ }
+
+ protected void thenCarFound(String brand) {
+ Session session = sessionFactory.openSession();
+ assertNotNull(session.get(Car.class, brand));
+ }
+
+ protected void thenCarNotFound(String brand) {
+ Session session = sessionFactory.openSession();
+ assertNull(session.get(Car.class, brand));
+ }
+
+ @SuppressWarnings("deprecation")
+ private void createCarTable() {
+ Session session = sessionFactory.openSession();
+ Transaction tx = session.beginTransaction();
+ session.createSQLQuery("drop table Car if exists")
+ .executeUpdate();
+ session.createSQLQuery("create table Car (brand varchar(255) primary key)")
+ .executeUpdate();
+ tx.commit();
+ }
+
+ private Properties getHibernateProperties() throws IOException {
+ Properties properties = new Properties();
+ properties.load(getClass().getResourceAsStream(getPropertyFile()));
+ return properties;
+ }
+
+ private static SessionFactory buildSessionFactory(Properties properties) {
+ ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(properties)
+ .build();
+ MetadataSources metadataSources = new MetadataSources(serviceRegistry);
+ metadataSources.addAnnotatedClass(Car.class);
+ return metadataSources.buildMetadata()
+ .buildSessionFactory();
+ }
+
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/database/DatabaseApproachMultitenancyIntegrationTest.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/database/DatabaseApproachMultitenancyIntegrationTest.java
new file mode 100644
index 0000000000..92f477a646
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/database/DatabaseApproachMultitenancyIntegrationTest.java
@@ -0,0 +1,25 @@
+package com.baeldung.hibernate.multitenancy.database;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+import com.baeldung.hibernate.multitenancy.MultitenancyIntegrationTest;
+
+public class DatabaseApproachMultitenancyIntegrationTest extends MultitenancyIntegrationTest {
+
+ @Override
+ public String getPropertyFile() {
+ return "/hibernate-database-multitenancy.properties";
+ }
+
+ @Test
+ public void givenDatabaseApproach_whenAddingEntries_thenOnlyAddedToConcreteDatabase() throws IOException {
+ whenCurrentTenantIs(TenantIdNames.MYDB1);
+ whenAddCar("myCar");
+ thenCarFound("myCar");
+ whenCurrentTenantIs(TenantIdNames.MYDB2);
+ thenCarNotFound("myCar");
+ }
+
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/database/MapMultiTenantConnectionProvider.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/database/MapMultiTenantConnectionProvider.java
new file mode 100644
index 0000000000..eb1f410622
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/database/MapMultiTenantConnectionProvider.java
@@ -0,0 +1,42 @@
+package com.baeldung.hibernate.multitenancy.database;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
+import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider;
+import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
+
+@SuppressWarnings("serial")
+public class MapMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider {
+
+ private final Map connectionProviderMap = new HashMap<>();
+
+ public MapMultiTenantConnectionProvider() throws IOException {
+ initConnectionProviderForTenant(TenantIdNames.MYDB1);
+ initConnectionProviderForTenant(TenantIdNames.MYDB2);
+ }
+
+ @Override
+ protected ConnectionProvider getAnyConnectionProvider() {
+ return connectionProviderMap.values()
+ .iterator()
+ .next();
+ }
+
+ @Override
+ protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
+ return connectionProviderMap.get(tenantIdentifier);
+ }
+
+ private void initConnectionProviderForTenant(String tenantId) throws IOException {
+ Properties properties = new Properties();
+ properties.load(getClass().getResourceAsStream(String.format("/hibernate-database-%s.properties", tenantId)));
+ DriverManagerConnectionProviderImpl connectionProvider = new DriverManagerConnectionProviderImpl();
+ connectionProvider.configure(properties);
+ this.connectionProviderMap.put(tenantId, connectionProvider);
+ }
+
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/database/TenantIdNames.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/database/TenantIdNames.java
new file mode 100644
index 0000000000..231272fa63
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/database/TenantIdNames.java
@@ -0,0 +1,6 @@
+package com.baeldung.hibernate.multitenancy.database;
+
+public class TenantIdNames {
+ public static final String MYDB1 = "mydb1";
+ public static final String MYDB2 = "mydb2";
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/schema/SchemaApproachMultitenancyIntegrationTest.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/schema/SchemaApproachMultitenancyIntegrationTest.java
new file mode 100644
index 0000000000..304af65fca
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/schema/SchemaApproachMultitenancyIntegrationTest.java
@@ -0,0 +1,26 @@
+package com.baeldung.hibernate.multitenancy.schema;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+import com.baeldung.hibernate.multitenancy.MultitenancyIntegrationTest;
+import com.baeldung.hibernate.multitenancy.database.TenantIdNames;
+
+public class SchemaApproachMultitenancyIntegrationTest extends MultitenancyIntegrationTest {
+
+ @Override
+ public String getPropertyFile() {
+ return "/hibernate-schema-multitenancy.properties";
+ }
+
+ @Test
+ public void givenSchemaApproach_whenAddingEntries_thenOnlyAddedToConcreteSchema() throws IOException {
+ whenCurrentTenantIs(TenantIdNames.MYDB1);
+ whenAddCar("Ferrari");
+ thenCarFound("Ferrari");
+ whenCurrentTenantIs(TenantIdNames.MYDB2);
+ thenCarNotFound("Ferrari");
+ }
+
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/schema/SchemaMultiTenantConnectionProvider.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/schema/SchemaMultiTenantConnectionProvider.java
new file mode 100644
index 0000000000..601eba651c
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/schema/SchemaMultiTenantConnectionProvider.java
@@ -0,0 +1,48 @@
+package com.baeldung.hibernate.multitenancy.schema;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
+import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider;
+import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
+
+@SuppressWarnings("serial")
+public class SchemaMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider {
+
+ private final ConnectionProvider connectionProvider;
+
+ public SchemaMultiTenantConnectionProvider() throws IOException {
+ connectionProvider = initConnectionProvider();
+ }
+
+ @Override
+ protected ConnectionProvider getAnyConnectionProvider() {
+ return connectionProvider;
+ }
+
+ @Override
+ protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
+ return connectionProvider;
+ }
+
+ @Override
+ public Connection getConnection(String tenantIdentifier) throws SQLException {
+ Connection connection = super.getConnection(tenantIdentifier);
+ connection.createStatement()
+ .execute(String.format("SET SCHEMA %s;", tenantIdentifier));
+ return connection;
+ }
+
+ private ConnectionProvider initConnectionProvider() throws IOException {
+ Properties properties = new Properties();
+ properties.load(getClass().getResourceAsStream("/hibernate-schema-multitenancy.properties"));
+
+ DriverManagerConnectionProviderImpl connectionProvider = new DriverManagerConnectionProviderImpl();
+ connectionProvider.configure(properties);
+ return connectionProvider;
+ }
+
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/schema/TenantIdNames.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/schema/TenantIdNames.java
new file mode 100644
index 0000000000..2eba94e307
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernate/multitenancy/schema/TenantIdNames.java
@@ -0,0 +1,6 @@
+package com.baeldung.hibernate.multitenancy.schema;
+
+public class TenantIdNames {
+ public static final String MYDB1 = "mydb1";
+ public static final String MYDB2 = "mydb2";
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernateparameters/NamedParameterUnitTest.java b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernateparameters/NamedParameterUnitTest.java
new file mode 100644
index 0000000000..4efa1e1f68
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/java/com/baeldung/hibernateparameters/NamedParameterUnitTest.java
@@ -0,0 +1,73 @@
+package com.baeldung.hibernateparameters;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistry;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.query.Query;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+public class NamedParameterUnitTest {
+ private SessionFactory sessionFactory;
+
+ @Before
+ public void setUp() throws Exception {
+ final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
+ .configure()
+ .build();
+ try {
+ sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
+ Session session = sessionFactory.openSession();
+ session.beginTransaction();
+ session.save(new Event("Event 1"));
+ session.save(new Event("Event 2"));
+ session.getTransaction().commit();
+ session.close();
+ } catch (Exception e) {
+ fail(e);
+ StandardServiceRegistryBuilder.destroy(registry);
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (sessionFactory != null) {
+ sessionFactory.close();
+ }
+ }
+
+ @Test
+ public void whenNamedParameterProvided_thenCorrect() {
+ Session session = sessionFactory.openSession();
+ session.beginTransaction();
+ Query query = session.createQuery("from Event E WHERE E.title = :eventTitle", Event.class);
+
+ // This binds the value "Event1" to the parameter :eventTitle
+ query.setParameter("eventTitle", "Event 1");
+
+ assertEquals(1, query.list().size());
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ @Test(expected = org.hibernate.QueryException.class)
+ public void whenNamedParameterMissing_thenThrowsQueryException() {
+ Session session = sessionFactory.openSession();
+ session.beginTransaction();
+ Query query = session.createQuery("from Event E WHERE E.title = :eventTitle", Event.class);
+
+ try {
+ query.list();
+ fail("We are expecting an exception!");
+ } finally {
+ session.getTransaction().commit();
+ session.close();
+ }
+ }
+}
diff --git a/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-database-multitenancy.properties b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-database-multitenancy.properties
new file mode 100644
index 0000000000..853fa80dfc
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-database-multitenancy.properties
@@ -0,0 +1,2 @@
+hibernate.multiTenancy=DATABASE
+hibernate.multi_tenant_connection_provider=com.baeldung.hibernate.multitenancy.database.MapMultiTenantConnectionProvider
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-database-mydb1.properties b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-database-mydb1.properties
new file mode 100644
index 0000000000..345f1dbbea
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-database-mydb1.properties
@@ -0,0 +1,4 @@
+hibernate.connection.driver_class=org.h2.Driver
+hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1
+hibernate.connection.username=sa
+hibernate.dialect=org.hibernate.dialect.H2Dialect
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-database-mydb2.properties b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-database-mydb2.properties
new file mode 100644
index 0000000000..626b7853c6
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-database-mydb2.properties
@@ -0,0 +1,4 @@
+hibernate.connection.driver_class=org.h2.Driver
+hibernate.connection.url=jdbc:h2:mem:mydb2;DB_CLOSE_DELAY=-1
+hibernate.connection.username=sa
+hibernate.dialect=org.hibernate.dialect.H2Dialect
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-exception.properties b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-exception.properties
new file mode 100644
index 0000000000..e08a23166d
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-exception.properties
@@ -0,0 +1,16 @@
+hibernate.connection.driver_class=org.h2.Driver
+hibernate.connection.url=jdbc:h2:mem:myexceptiondb1;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
+
+hibernate.transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
diff --git a/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-schema-multitenancy.properties b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-schema-multitenancy.properties
new file mode 100644
index 0000000000..4abb621355
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-schema-multitenancy.properties
@@ -0,0 +1,7 @@
+hibernate.connection.driver_class=org.h2.Driver
+hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS MYDB1\\;CREATE SCHEMA IF NOT EXISTS MYDB2\\;
+hibernate.connection.username=sa
+hibernate.connection.autocommit=true
+hibernate.dialect=org.hibernate.dialect.H2Dialect
+hibernate.multiTenancy=SCHEMA
+hibernate.multi_tenant_connection_provider=com.baeldung.hibernate.multitenancy.schema.SchemaMultiTenantConnectionProvider
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-spatial.properties b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-spatial.properties
new file mode 100644
index 0000000000..1657c838e3
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate-spatial.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.spatial.dialect.h2geodb.GeoDBDialect
+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-enterprise/src/test/resources/hibernate.properties b/persistence-modules/hibernate5-enterprise/src/test/resources/hibernate.properties
new file mode 100644
index 0000000000..c14782ce0f
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/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-enterprise/src/test/resources/lifecycle-init.sql b/persistence-modules/hibernate5-enterprise/src/test/resources/lifecycle-init.sql
new file mode 100644
index 0000000000..c0c9a3f34d
--- /dev/null
+++ b/persistence-modules/hibernate5-enterprise/src/test/resources/lifecycle-init.sql
@@ -0,0 +1,25 @@
+create sequence hibernate_sequence start with 1 increment by 1;
+
+create table Football_Player (
+ id bigint not null,
+ name varchar(255),
+ primary key (id)
+);
+
+insert into
+ Football_Player
+ (name, id)
+ values
+ ('Cristiano Ronaldo', next value for hibernate_sequence);
+
+insert into
+ Football_Player
+ (name, id)
+ values
+ ('Lionel Messi', next value for hibernate_sequence);
+
+insert into
+ Football_Player
+ (name, id)
+ values
+ ('Gigi Buffon', next value for hibernate_sequence);
\ No newline at end of file
diff --git a/persistence-modules/hibernate5-enterprise/src/test/resources/profile.png b/persistence-modules/hibernate5-enterprise/src/test/resources/profile.png
new file mode 100644
index 0000000000..1cd4e978b9
Binary files /dev/null and b/persistence-modules/hibernate5-enterprise/src/test/resources/profile.png differ