Hibernate Entity Object States | LifeCycle States

Hibernate Entity persistent object can be in four different states transient, persistent, detached.

Hibernate basically works on a java object and that java object when linked with hibernate annotations passes through these states in its complete lifecycle.

Let’s look at all the Three lifecycle states:

1. Transient Object

An object is transient if it has just been instantiated using the new operator, and it is not associated with a Hibernate Session.

Hibernate will detect any changes made to an object in persistent state and synchronize the state with the database when the unit of work completes.

2. Persistent Object

Persistent objects exist in the database, and Hibernate manages the persistence for persistent objects.

3. Detached Object

A detached instance is an object that has been in the persistent state, but its Session has been closed. The reference to the object is still valid, of course, and the detached instance might even be modified in this state.

Summary

In this article we read about the Hibernate Entity Object States or the LifeCycle States, how hibernate maintains the lifecycle of an entity object.
I hope you liked the article !


Hibernate Native Query with example

You can express a query in SQL, using createSQLQuery() and let Hibernate manage the mapping from result sets to objects.

Although we should use HQL wherever possible but there could be a few reasons where you want to use native SQL funtionalities, such as :

  1. Calling stored procedures
  2. Calling stored functions
  3. DB support some special features which are not present in HQL

How to write a native query in hibernate ?

You can specify all properties on an object with {objectname.*}, or you can specify the aliases directly with {objectname.property}.

public SQLQuery createSQLQuery(String queryString) throws 
                                                                                                   HibernateException

If using Oracle DB: using ROWNUM

List emps = session.createSQLQuery("SELECT {emp.*} FROM Employee 
                {emp} WHERE ROWNUM<10")
                .addEntity("emp", Employee.class)
                .list();
        System.out.println("Native Query result list :: "+emps);

If using mySql DB: using LIMIT

List emps = session.createSQLQuery("SELECT {emp.*} FROM Employee 
                {emp} LIMIT 10")
                .addEntity("emp", Employee.class)
                .list();
        System.out.println("Native Query result list :: "+emps);

Output

Native Query result list ::
[Employee{id=2, firstName='Mak', lastName='S', address='mak@pt.com'}, 
Employee{id=3, firstName='Mak', lastName='S', address='mak@pt.com'},  
Employee{id=4, firstName='mak', lastName='robins', address='NA'}]

Summary

In this article, we looked into Hibernate Native Query with some example, the reason why to use native query and when to use it.
I hope you liked the article !


Hibernate Interceptors with Example

In Hibernate, interceptors are used to inspect the changes in entity’s property values before they are written and after they are read from a database.

You can use the Hibernate interceptor to perform the various operations such as logging, auditing, profiling etc.

1. Registering Interceptors

In Hibernate, an interceptor can either be Session-scoped or SessionFactory-scoped.

1. Session-scoped interceptors are used when a Session is opened. The following code snippet shows how to add an interceptor to a Session.

Session session = HibernateUtil.getSessionFactory()
	.withOptions()
	.interceptor(new MyLogInterceptor())
	.openSession();

2. SessionFactory-scoped or global interceptors are used when SessionFactory is configured and these interceptors will be applied to applied to all Session opened from that SessionFactory. The following code snippet shows how to add an interceptor to a SessionFactory.

SessionFactory sessionFactory = metadata.getSessionFactoryBuilder()
	.applyInterceptor(new MyLogInterceptor())
	.build();

2. How to Create Hibernate Interceptors?

There are two ways of defining interceptors:

1. implementing the org.hibernate.Interceptor interface
2. extending the org.hibernate.EmptyInterceptor class 

There are around 14 callback methods which the interceptor provides for us to override and use.

Some of them are onLoad, onDelete, onSave, onFlushDirty, findDirty, etc

If you are creating your interceptor implementing the Interceptor interface then you may need to override all the methods provided.

Instead of implementing this interface directly, it is usually better to extend EmptyInterceptor and override only the callback methods of interest.

3. Example Hibernate Interceptor

1. Create Interceptor Class

By extending EmptyInterceptor Class

import com.pt.entities.Employee;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import java.io.Serializable;

public class MyLogInterceptor extends EmptyInterceptor {

    public boolean onSave(Object entity, Serializable id, Object[] state,
                          String[] propertyNames, Type[] types) {
        if (entity instanceof Employee) {
            Employee emp = (Employee) entity;
            System.out.println(emp.toString());
        }
        return super.onSave(entity, id, state, propertyNames, types);
    }
}

2. Employee Entity looks like this

Create your own set of Entity class like this.

@Entity
@Table(name = "Employee")
@NamedQueries({
        @NamedQuery(name = "Employee.findAll", query = "from Employee emp"),
        @NamedQuery(name = "Employee.findByName",
                query = "from Employee emp where emp.firstName=:firstName"),
})
public class Employee implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;

// getters & setters & toString()
// ...
}

3. Create HibernateUtility Class – to create session a session factory

Below is the code of HibernateUtility Class – in this we are creating a sessionfactory and registering our Employee Enitity class.

package com.pt.standalone;

import com.pt.entities.Employee;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Environment;

import java.util.HashMap;
import java.util.Map;

public class HibernateUtility {

    private static StandardServiceRegistry registry;
    private static SessionFactory sessionFactory;

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {

                // Create registry builder
                StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();

                // Hibernate settings equivalent to hibernate.cfg.xml's properties
                Map<String, String> settings = new HashMap<>();
                settings.put(Environment.DRIVER, "com.mysql.cj.jdbc.Driver");
                settings.put(Environment.URL, "jdbc:mysql://localhost:3306/testdb");
                settings.put(Environment.USER, "root");
                settings.put(Environment.PASS, "root");
                settings.put(Environment.DIALECT, "org.hibernate.dialect.MySQL57Dialect");

                // Apply settings
                registryBuilder.applySettings(settings);

                // Create registry
                registry = registryBuilder.build();

                // Create MetadataSources
                MetadataSources sources = new MetadataSources(registry).addAnnotatedClass(Employee.class);

                // Create Metadata
                Metadata metadata = sources.getMetadataBuilder().build();

                // Create SessionFactory

                sessionFactory = metadata.getSessionFactoryBuilder().build();
            } catch (Exception e) {
                e.printStackTrace();
                if (registry != null) {
                    StandardServiceRegistryBuilder.destroy(registry);
                }
            }
        }
        return sessionFactory;
    }

    public static void shutdown() {
        if (registry != null) {
            StandardServiceRegistryBuilder.destroy(registry);
        }
    }
}

4. Run – main method Class

Now run the main class.

import com.pt.entities.Employee;
import org.hibernate.Session;

public class TestHB {

    public static void main(String[] args) {

        Session session = HibernateUtility.getSessionFactory().withOptions().
                interceptor(new MyLogInterceptor()).openSession();
        session.beginTransaction();
        
        System.out.println("Save Employee...");

        // saving an object
        Employee emp = new Employee(10,"mak","robins","NA");
        session.save(emp);
  }
}

5. Output

Save Employee...
Employee{id=10, firstName='mak', lastName='robins', address='NA'}

Summary

In this article, we learnt about Hibernate Interceptors, how to create hibernate interceptors, its various uses and a working example.
I hope you liked it !


Hibernate Named Query

Hibernate Named Queries are created via class-level annotations on entities; normally, the queries apply to the entity in whose source file they occur, but there’s no absolute requirement for this to be true.

Named queries are created with the @NamedQueries annotation, which contains an array of @NamedQuery sets; each has a query and a name.

Example :

@Entity
@Table(name = "Employee")
@NamedQueries({
        @NamedQuery(name = "Employee.findAll", query = "from Employee emp"),
        @NamedQuery(name = "Employee.findByName",
                query = "from Employee emp where emp.firstName=:firstName"),
})
public class Employee implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;

// getters & setters & toString()
// ...
}

Executing above named query  :

Query namedQuery = session.getNamedQuery("Employee.findAll");
List<Employee> employees = namedQuery.list();
employees.forEach(System.out::println);  

Summary

In this tutorial, we learnt about what is hibernate named query and understood by seeing an example of how to declare a named query.
I hope you liked it !


Hibernate Query Language | HQL examples

Hibernate Query Language a.k.a HQL is a query language which deals directly with the persistent entity object instead of the database table directly.

In this section we will see what is hibernate query language, syntax to write various kinds of HQL like Select, updates, insert, delete.

Syntax

Query query=session.createQuery("HQL query comes here....Example.... 
FROM Employee set age=:age where name=:name");

1. SELECT Query

You can write it as “Select * from employee” or as “From Employee”.

Example:

Query query = session.createQuery("From Employee");
List<Employee> list = query.getResultList();

2. Update Query

Example:

Query query=session.createQuery("update Employee 
                                set age=:age where name=:name");
query.setInteger("age", 30);
query.setString("name", "John Doe");
int result=query.executeUpdate();
System.out.println("Rows affected: " + result);

3. Insert Query

Example:

String hql = "INSERT INTO Employee(firstName, lastName, address)"
           + "SELECT firstName, lastName, address FROM old_employee"
           + "where id=:id";
Query query = session.createQuery(hql);
query.setString("id", 101);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

4. Delete Query

Example:

String hql = "DELETE FROM Employee "  + 
             "WHERE id = :emp_id";
Query query = session.createQuery(hql);
query.setParameter("emp_id", 101);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

5. Pagination in HQL Query

Two methods to set the start and end positions.

Query setFirstResult(int startPosition) : start index position
Query setMaxResults(int maxResult) : number of results from the index set above

Example:

String hql = "FROM Employee";
Query query = session.createQuery(hql);
query.setFirstResult(5);
query.setMaxResults(10);
List results = query.list();

6. Aggregate functions in HQL Query

The aggregate functions available in HQL includes the following:

  1. avg(property name): The average of a property’s value.
  2. count(property name or *): The number of times a property occurs in the results.
  3. min(property name): The minimum value of the property values.
  4. max(property name): The maximum value of the property values.
  5. sum(property name): The sum total of the property values.

Example:

String hql = "SELECT count(distinct Emp.firstName) FROM Employee Emp";
Query query = session.createQuery(hql);
List results = query.list();

Summary

In this tutorial we learnt how to write HQL(hibernate query language) which is simple, easy for java developers. We went through CRUD operations syntax and examples in HQL, then went through the pagination and aggregate functions with examples.
I hope you liked it !


Hibernate Cache Levels

Hibernate has 2 Cache’s, First level default session cache and the Second level explicitly configured cache. The main purpose of Cache’s is to reduce the number of Database hits from the application.

In this tutorial, You will find a very Simple easy to follow example using ehcache configuration as second level cache in hibernate.

When does Hibernate Use Second level Cache ?

  1. When Hibernate Session try to load an entity, it looks for the value in first level cache. If the cached copy is present in the first level cache then it is returned on call to load() method.
  2. If there is no cached entity in first level cache then it looks in the second level cache. If the entity is cached in second level then it is returned as result of load() method. But before returning the entity, it is stored in first level cache, so that for the next invocation the entity is loaded from the first level cache and not the second again.
  3. If the entity is not found in first and the second level cache, then the entity data is fetched from the database itself and is also stored in both the caches before returning the response.

How do cache verify updated data ?

  1. Second level cache validate itself for modified entities, if modification has been done through hibernate session APIs.
  2. But in some cases where someone modifies the data directly inside the database then that data will not be cached itself in the second level cache until “timeToLiveSeconds” duration has passed for that cache region. In that case, you can invalidate the cache and let hibernate build it again.

Configure EhCache

1. Add ehcache dependency in pom.xml

<dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-ehcache</artifactId>
     <version>5.4.11.Final</version>
</dependency>

2. Add ehcache properties in properties file

You can add the cache properties in any property files like the “application.properties” or you name it anything and keep it in the resource folder of the project.

In this example, i have placed the properties in a file called “db.properties”.

# Hibernate Second level Cache
hibernate.cache.use_second_level_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory

3. Add @ annotations in Entity Objects Class

For Example : Employee.java

add @Cacheable & @org.hibernate.annotations.Cache

package com.pt.entities;

import org.hibernate.annotations.CacheConcurrencyStrategy;

import javax.persistence.*;

@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
@Table(name = "EMPLOYEE")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;

    public Employee() {}

    public Employee(int id, String firstName, 
                    String lastName, String address) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public void setId( int id ) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName( String first_name ) {
        this.firstName = first_name;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName( String last_name ) {
        this.lastName = last_name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

4. Service method call

In the basic code example in our previous tutorial add the below method in DAO implementation layer.

We will create 2 sessions and try to load the same Employee for example of id=6.

private void getEmployee() {

System.out.println("We are inside getEmployee method...");

Session session = sessionFactory.openSession();
Employee emp = session.load(Employee.class,6);
System.out.println("Employee load 1st time");
System.out.println(emp.getId()+" "+emp.getFirstName()+" "
                   +emp.getLastName());

Session session2 = sessionFactory.openSession();
Employee emp2 = session2.load(Employee.class,6);
System.out.println("Employee load 2nd time");
System.out.println(emp2.getId()+" "+emp2.getFirstName()+" "
                   +emp2.getLastName());

}

5. Output

Observation : Please see carefully in the below output, you will find there is only one select query on 1st load time, and no select query call on second call of load method,
this means that 1st time when the entity is loaded, it is being loaded from the database and internally also sent to both the caches before returning the entity object, but the 2nd time the data was loaded from the second level Cache itself(why not from the First level cache – the answer is because since we are using 2 different session objects in this example).

INFO: HHH000490: Using JtaPlatform implementation: 
 [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
We are inside getEmployee method...
Employee load 1st time
Hibernate: select employee0_.id as id1_0_0_, employee0_.address as 
address2_0_0_, employee0_.first_name as first_na3_0_0_, 
employee0_.last_name as last_nam4_0_0_ from EMPLOYEE employee0_ 
where employee0_.id=?
6 Mak S
Employee load 2nd time
6 Mak S

Summary

In this tutorial, we learnt and experienced in details how hibernate cache’s work. Try out the above code in your system and let us know your experience in comments.
I hope you liked it !


Hibernate Entity Mappings

Now as you you have seen in the previous article how to create an Entity, now let’s see how to create relationships between Entities also called as Entity mappings, JPA defines four annotations for defining entities:

1. @OneToOne
2. @OneToMany
3. @ManyToOne
4. @ManyToMany

1. One-to-one relationships

The @OneToOne annotation is used to define a one-to-one relationship between two entities.

For example, you have a table EMPLOYEE and you want to store employee’s personal information(such as age, gender and grade) in another table, in that case you create another Entity and map both the entities by @OneToOne mapping, one instance of an Employee Entity class mapped to one instance of EmployeeProfile Entity.

import javax.persistence.*;

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id @GeneratedValue
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;
	
    @OneToOne(mappedBy="emp")
    private EmployeeProfile profile;
	...
	
}
@Entity
public class EmployeeProfile {
   @Id
   private Integer id;
   private int age;
   private String gender;
   private String grade;
   @OneToOne
   private Employee emp;
   ...
}

The JPA provider uses EmployeeProfile’s emp field to map EmployeeProfile to Employee. The mapping is specified in the mappedBy attribute in the @OneToOne annotation.

2. One-to-many and many-to-one relationships

The @OneToMany and @ManyToOne annotations facilitate both sides of the same relationship.

Here’s an example where one Employee can have multiple Projects and a Project may have many other employees as well.
The Employee entity would define a @ManyToMany relationship with Project and the Project Entity would define a @OneToMany relationship with an Employee.

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id @GeneratedValue
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

	@ManyToOne
    @JoinColumn(name="PROJECT_ID")
    private Project project;
	...
}
@Entity
public class Project {
   @Id
   private Integer projectId;
   private String projectDescription;
   private String projectDuration;
   @OneToMany(mappedBy = "project")
   private List<Employee> emp = new ArrayList<>();
   ...
}

3. many-to-many relationships

Here’s a case where an Employee entity has many projects.

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id @GeneratedValue
    @Column(name = "EMP_ID")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

	@ManyToMany
    @JoinTable(name="EMP_PROJECTS",
    		   joinColumns=@JoinColumn(name="EMP_ID"),
    		   inverseJoinColumns=@JoinColumn(name="PROJECT_ID"))
    private Set<Project> projects = new HashSet<>();
	...
}
@Entity
public class Project {
   @Id
   private Integer projectId;
   private String projectDescription;
   private String projectDuration;
  
   @ManyToMany(mappedBy = "projects")
   private Set<Employee> projects = new HashSet<>();
   ...
}

In this example, we create a new table, EMP_PROJECTS, with two columns: EMP_ID and PROJECT_ID. Using the joinColumns and inverseJoinColumns attributes tells your JPA framework how to map these classes in a many-to-many relationship. The @ManyToMany annotation in the Employee class references the field in the Project class that manages the relationship; namely the projects property.

Summary

In this article we looked into the relational mapping between tables or entities in a JPA ORM way.
Hope you liked it !


Hibernate Criteria Query

Hibernate Criteria Query API lets you create nested, structured query expressions in Java, it gives you an object oriented control over the queries, it provides a compile time syntax check which is not possible with a query language like HQL or SQL.

Since Hibernate 5.2, the Hibernate Criteria API is deprecated and 
new development is focused on the JPA Criteria API.

Hibernate version that We are using here :

<dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-core</artifactId>
     <version>5.4.11.Final</version>
</dependency>

Hibernate Criteria Query : Example

Employee Entity

@Entity
@Table(name = "Employee")
public class Employee implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;

// getters & setters & toString()
// ...
}

Fetch Employees from the Database using Criteria Query

// Criteria Query Example
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Employee> cr = cb.createQuery(Employee.class);
Root<Employee> root = cr.from(Employee.class);
cr.select(root);

Query criteriaQuery = session.createQuery(cr);
List<Employee> results = query.getResultList();
results.forEach(System.out::println); // print all Employee records

Explanation Step by Step :

  1. Create an instance of Session from the SessionFactory object
  2. Create an instance of CriteriaBuilder by calling the getCriteriaBuilder() method
  3. Create an instance of CriteriaQuery by calling the CriteriaBuilder createQuery() method
  4. Create an instance of Query by calling the Session createQuery() method
  5. Call the getResultList() method of the query object which gives us the results
  6. At last using java 8 for each loop to print the records.

Summary

In this tutorial, we focused on the basics of Criteria Queries in Hibernate and JPA,
Hope you liked it !


Hibernate Cascading Levels

In Simple terms, Cascading in Hibernate means the propagation of same action(for eg: save, delete, etc.) from Parent to Child level entity.

Depending on what type of action to perform there are different cascade types.

Let’s have a look at an example:

Employee.java Entity Class

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id @GeneratedValue
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name="EMPLOYEE_ID")
    private Set<Project> projects;
	...
}

Project.java Entity Class

@Entity
public class Project {
   @Id
   private Integer projectId;
   private String projectDescription;
   private String projectDuration;
  
   @OneToOne (mappedBy="projects",  fetch = FetchType.LAZY)
   private Employee employee;
   ...
}

cascade=CascadeType.ALL” essentially means that any change which happens on Employee Entity must cascade to Project Entity as well. If you save an employee, then all associated projects will also be saved into database. If you delete an Employee then all projects associated with that Employee will also be deleted.

But what if we only want to cascade only save operations but not delete operation. Then we need to clearly specify it using correct CascadeType, see the below code.

@OneToMany(cascade=CascadeType.PERSIST, fetch = FetchType.LAZY)
@JoinColumn(name="EMPLOYEE_ID")
private Set<Project> projects;

Now only when save() or persist() methods are called using employee instance then only projects will be persisted. If any other method is called on session, it’s effect will not affect/cascade to projects.

JPA – Cascade Types

The cascade types supported by the Java Persistence Architecture are as below:

  1. CascadeType.PERSIST : cascade type presist means that save() or persist() operations cascade to related entities.
  2. CascadeType.MERGE : cascade type merge means that related entities are merged when the owning entity is merged.
  3. CascadeType.REFRESH : cascade type refresh does the same thing for the refresh() operation.
  4. CascadeType.REMOVE : cascade type remove removes all related entities association with this setting when the owning entity is deleted.
  5. CascadeType.DETACH : cascade type detach detaches all related entities if a “manual detach” occurs.
  6. CascadeType.ALL : cascade type all is shorthand for all of the above cascade operations.

There is no default cascade type in JPA. By default no operations are cascaded.

Hibernate – Cascade Types

Now lets understand what is cascade in hibernate in which scenario we use it.

Apart from JPA provided cascade types, there is one more cascading operation in hibernate which is not part of the normal set above discussed, called “orphan removal“. This removes an owned object from the database when it’s removed from its owning relationship.

Let’s understand with an example. In our Employee and Project entity example, I have updated them as below and have mentioned “orphanRemoval = true” on projects. It essentially means that whenever I will remove a ‘ project from projects set’ (which means I am removing the relationship between that project and Employee); the project entity which is not associated with any other Employee on database (i.e. orphan) should also be deleted.

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id @GeneratedValue
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @OneToMany(orphanRemoval = true, mappedBy = "employee")
    private Set<Project> projects;
	...
}

Summary

In this tutorial, we have seen different ways to use cascade type operations in JPA hibernate.
I hope you liked it !


Spring 5 + Hibernate 5 integration Only annotations without xml configuration

Learn How to Create a Spring 5 + Hibernate 5 application using Only annotations without xml configuration in really easy way.

Let’s Begin Coding

1. Final Project Structure – will look like this

spring-hibernate-with-annotations-project-structure

2. Add jar dependencies to pom.xml

In this project we will use Spring 5, Hibernate 5 and mySql DB stack.

To use the above technology stack add the following dependencies in your pom.xml file as below.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>SpringHibernate</groupId>
    <artifactId>com.pt</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/
             org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/
             org.springframework/spring-orm -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/
             mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/
             org.hibernate/hibernate-core -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.4.11.Final</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/
             org.apache.commons/commons-dbcp2 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.7.0</version>
        </dependency>

        </dependency>
    </dependencies>

    <build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
    </build>

</project>

2. Create Entity Class

Employee.java Entity Class

package com.pt.entities;

import javax.persistence.*;

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "address")
    private String address;

    public Employee() {}

    public Employee(int id, String firstName, 
                    String lastName, String address) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public void setId( int id ) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName( String first_name ) {
        this.firstName = first_name;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName( String last_name ) {
        this.lastName = last_name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

3. Create DAO Layer

Create Data Access Object layer:
1. Dao Interface
2. Dao Implementation Class

EmployeeDao.java Interface

package com.pt.dao;

import com.pt.entities.Employee;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeDao {

        void add(Employee employee);

}

EmployeeDaoImpl.java Class

package com.pt.dao;

import com.pt.entities.Employee;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class EmployeeDaoImpl implements EmployeeDao {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public void add(Employee employee) {
        sessionFactory.getCurrentSession().save(employee);
    }
}

4. Create Service Layer

Create Service layer:
1. Service Interface
2. Service Implementation Class

EmployeeService.java Interface

package com.pt.services;

import com.pt.entities.Employee;


public interface EmployeeService {

    void add(Employee employee);

}

EmployeeServiceImpl.java Class

package com.pt.services;

import com.pt.dao.EmployeeDao;
import com.pt.entities.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class EmployeeServiceImpl implements EmployeeService {

    @Autowired
    public EmployeeDao employeeDao;

    @Transactional
    @Override
    public void add(Employee employee) {
        employeeDao.add(employee);
    }
}

5. Create db.properties File

db.properties

# MySQL properties
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/testdb
db.username=root
db.password=root

# Hibernate properties
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
hibernate.dialect=org.hibernate.dialect.MySQL57Dialect

6. Create Configs Class File

AppConfig.Java Class

package com.pt.configs;

import com.pt.entities.Employee;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
@PropertySource("classpath:db.properties")
@EnableTransactionManagement
@ComponentScans(value = {
        @ComponentScan("com.pt.dao"),
        @ComponentScan("com.pt.services")
})

public class AppConfig {

        @Autowired
        private Environment env;

        @Bean
        public DataSource getDataSource() {
            BasicDataSource dataSource = new BasicDataSource();
            dataSource.setDriverClassName(env.getProperty("db.driver"));
            dataSource.setUrl(env.getProperty("db.url"));
            dataSource.setUsername(env.getProperty("db.username"));
            dataSource.setPassword(env.getProperty("db.password"));
            return dataSource;
        }

        @Bean
        public LocalSessionFactoryBean getSessionFactory() {
            LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
            factoryBean.setDataSource(getDataSource());

            Properties props=new Properties();
            props.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
            props.put("hibernate.dialect",env.getProperty("hibernate.dialect"));
            props.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
            factoryBean.setHibernateProperties(props);
            factoryBean.setAnnotatedClasses(Employee.class);
            return factoryBean;
        }

        @Bean
        public HibernateTransactionManager getTransactionManager() {
            HibernateTransactionManager transactionManager = new HibernateTransactionManager();
            transactionManager.setSessionFactory(getSessionFactory().getObject());
            return transactionManager;
        }
}

7. Last – Create main() method Class File

StartApp.java Class

package com.pt;

import com.pt.configs.AppConfig;
import com.pt.entities.Employee;
import com.pt.services.EmployeeService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.sql.SQLException;

public class StartApp {

    public static void main(String[] args) throws InterruptedException, SQLException {
        System.out.println("This is the start of the PT Spring Hibernate application");
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);

        EmployeeService employeeService = context.getBean(EmployeeService.class);

        // Add Employee
        employeeService.add(new Employee(1,"Mak", "S", "mak@pt.com"));

        context.close();
    }
}

OUTPUT

console log

"C:\Program Files\Java\jdk1.8.0_201\bin\java.exe" ...
This is the start of the PT Spring Hibernate application
Feb 13, 2020 10:22:46 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {5.4.11.Final}
Feb 13, 2020 10:22:47 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
Feb 13, 2020 10:22:54 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL57Dialect
Feb 13, 2020 10:22:57 PM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
Hibernate: insert into EMPLOYEE (address, first_name, last_name) values (?, ?, ?)

Process finished with exit code 0

In Database – The record is successfully inserted in the database.

mysql> select * from employee;
+----+------------+------------+-----------+
| id | address    | first_name | last_name |
+----+------------+------------+-----------+
|  1 | mak@pt.com | Mak        | S         |
+----+------------+------------+-----------+
1 row in set (0.00 sec)

Summary

In this tutorial, we learnt how to Create a Spring 5 + Hibernate 5 application using Only annotations without xml configuration in really easy way.
Hope you liked it !