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