Java Hibernate 5 Tutorial for Beginners
1. Preparing the Database
Hibernate is a library formed in order to work with all types of DB, it does not depend on any types of DB you choose". If Java is "Write once, run anywhere", Hibernate will be "Write one, run on all types of DB".
In the post, I use the simplehr, which is a simple database used in lots of tutorials on o7planning. You can create it with one of the databases such as Oracle, MySQL or SQL Server. Let's see the guideline below:
2. Create Maven Project & Declare library
Here, I create a Maven project and declare the Hibernate libraries in pom.xml.
- File/New/Other...
Project is created.
In pom.xml, I delare the Hibernate 5 library, and the JDBC libraries for the various database types such as Oracle, MySQL and SQL Server.
pom.xml
<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>org.o7planning</groupId>
<artifactId>HibernateTutorial</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>HibernateTutorial</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<!-- Repository for ORACLE JDBC Driver -->
<repository>
<id>codelds</id>
<url>https://code.lds.org/nexus/content/groups/main-repo</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- Hibernate Core -->
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.2.Final</version>
</dependency>
<!-- MySQL JDBC driver -->
<!-- http://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
<!-- Oracle JDBC driver -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
<!-- SQLServer JDBC driver (JTDS) -->
<!-- http://mvnrepository.com/artifact/net.sourceforge.jtds/jtds -->
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
</project>
3. Entity classes
We create class Entity. Each Entity describes a table in DB. Wait a minute, don't talk about anything in those classes.
- Department
- Employee
- SalaryGrade
- Timekeeper
Department.java
package org.o7planning.tutorial.hibernate.entities;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@Entity
@Table(name = "DEPARTMENT",
uniqueConstraints = { @UniqueConstraint(columnNames = { "DEPT_NO" }) })
public class Department {
private Integer deptId;
private String deptNo;
private String deptName;
private String location;
private Set<Employee> employees = new HashSet<Employee>(0);
public Department() {
}
public Department(Integer deptId, String deptName, String location) {
this.deptId = deptId;
this.deptNo = "D" + this.deptId;
this.deptName = deptName;
this.location = location;
}
@Id
@Column(name = "DEPT_ID")
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
@Column(name = "DEPT_NO", length = 20, nullable = false)
public String getDeptNo() {
return deptNo;
}
public void setDeptNo(String deptNo) {
this.deptNo = deptNo;
}
@Column(name = "DEPT_NAME", nullable = false)
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
@Column(name = "LOCATION")
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "department")
public Set<Employee> getEmployees() {
return employees;
}
public void setEmployees(Set<Employee> employees) {
this.employees = employees;
}
}
Employee.java
package org.o7planning.tutorial.hibernate.entities;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
@Entity
@Table(name = "EMPLOYEE",
uniqueConstraints = { @UniqueConstraint(columnNames = { "EMP_NO" }) })
public class Employee {
private Long empId;
private String empNo;
private String empName;
private String job;
private Employee manager;
private Date hideDate;
private Float salary;
private byte[] image;
private Department department;
private Set<Employee> employees = new HashSet<Employee>(0);
public Employee() {
}
public Employee(Long empId, String empName, String job, Employee manager,
Date hideDate, Float salary, Float comm, Department department) {
this.empId = empId;
this.empNo = "E" + this.empId;
this.empName = empName;
this.job = job;
this.manager = manager;
this.hideDate = hideDate;
this.salary = salary;
this.department = department;
}
@Id
@Column(name = "EMP_ID")
public Long getEmpId() {
return empId;
}
public void setEmpId(Long empId) {
this.empId = empId;
}
@Column(name = "EMP_NO", length = 20, nullable = false)
public String getEmpNo() {
return empNo;
}
public void setEmpNo(String empNo) {
this.empNo = empNo;
}
@Column(name = "EMP_NAME", length = 50, nullable = false)
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
@Column(name = "JOB", length = 30, nullable = false)
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "MNG_ID")
public Employee getManager() {
return manager;
}
public void setManager(Employee manager) {
this.manager = manager;
}
@Column(name = "HIRE_DATE", nullable = false)
@Temporal(TemporalType.DATE)
public Date getHideDate() {
return hideDate;
}
public void setHideDate(Date hideDate) {
this.hideDate = hideDate;
}
@Column(name = "SALARY", nullable = false)
public Float getSalary() {
return salary;
}
public void setSalary(Float salary) {
this.salary = salary;
}
@Column(name = "IMAGE", length = 1111111, nullable = true)
@Lob
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "DEPT_ID", nullable = false)
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "empId")
public Set<Employee> getEmployees() {
return employees;
}
public void setEmployees(Set<Employee> employees) {
this.employees = employees;
}
}
SalaryGrade.java
package org.o7planning.tutorial.hibernate.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "SALARY_GRADE")
public class SalaryGrade {
private Integer grade;
private Float lowSalary;
private Float highSalary;
public SalaryGrade() {
}
public SalaryGrade(Integer grade, Float lowSalary, Float highSalary) {
this.grade = grade;
this.lowSalary = lowSalary;
this.highSalary = highSalary;
}
@Id
@Column(name = "GRADE")
public Integer getGrade() {
return grade;
}
public void setGrade(Integer grade) {
this.grade = grade;
}
@Column(name = "LOW_SALARY", nullable = false)
public Float getLowSalary() {
return lowSalary;
}
public void setLowSalary(Float lowSalary) {
this.lowSalary = lowSalary;
}
@Column(name = "HIGH_SALARY", nullable = false)
public Float getHighSalary() {
return highSalary;
}
public void setHighSalary(Float highSalary) {
this.highSalary = highSalary;
}
}
Timekeeper.java
package org.o7planning.tutorial.hibernate.entities;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name = "TIMEKEEPER")
public class Timekeeper {
public static final char IN = 'I';
public static final char OUT = 'O';
private String timekeeperId;
private Date dateTime;
private Employee employee;
// 'I' or 'O'
private char inOut;
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
@Column(name = "Timekeeper_Id", length = 36)
public String getTimekeeperId() {
return timekeeperId;
}
public void setTimekeeperId(String timekeeperId) {
this.timekeeperId = timekeeperId;
}
@Column(name = "Date_Time", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
public Date getDateTime() {
return dateTime;
}
public void setDateTime(Date dateTime) {
this.dateTime = dateTime;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "EMP_ID", nullable = false)
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
@Column(name = "In_Out", nullable = false, length = 1)
public char getInOut() {
return inOut;
}
public void setInOut(char inOut) {
this.inOut = inOut;
}
}
4. Configure Hibernate
The purpose is that Hibernate can read Database as well as declare the list of Entities you created in the previous steps.
Create hibernate.cfg.xml configuration file located in src/main/java.
hibernate.cfg.xml (ORACLE)
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:db11g</property>
<property name="hibernate.connection.username">simplehr</property>
<property name="hibernate.connection.password">12345</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.connection.release_mode">auto</property>
<property name="current_session_context_class">thread</property>
<property name="hibernate.connection.autoReconnect">true</property>
<mapping class="org.o7planning.tutorial.hibernate.entities.Department" />
<mapping class="org.o7planning.tutorial.hibernate.entities.Employee" />
<mapping class="org.o7planning.tutorial.hibernate.entities.SalaryGrade" />
<mapping class="org.o7planning.tutorial.hibernate.entities.Timekeeper" />
</session-factory>
</hibernate-configuration>
hibernate.cfg.xml (MySQL)
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://tran-vmware:3306/simplehr?serverTimezone=UTC</property>
<property name="connection.username">root</property>
<property name="connection.password">1234</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<mapping class="org.o7planning.tutorial.hibernate.entities.Department" />
<mapping class="org.o7planning.tutorial.hibernate.entities.Employee" />
<mapping class="org.o7planning.tutorial.hibernate.entities.SalaryGrade" />
<mapping class="org.o7planning.tutorial.hibernate.entities.Timekeeper" />
</session-factory>
</hibernate-configuration>
hibernate.cfg.xml (SQL Server)
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">net.sourceforge.jtds.jdbc.Driver</property>
<property name="connection.url">jdbc:jtds:sqlserver://localhost:1433/simplehr;instance=SQLEXPRESS</property>
<property name="connection.username">sa</property>
<property name="connection.password">1234</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.SQLServerDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<mapping class="org.o7planning.tutorial.hibernate.entities.Department" />
<mapping class="org.o7planning.tutorial.hibernate.entities.Employee" />
<mapping class="org.o7planning.tutorial.hibernate.entities.SalaryGrade" />
<mapping class="org.o7planning.tutorial.hibernate.entities.Timekeeper" />
</session-factory>
</hibernate-configuration>
Each Database has an individual Dialect
For example:
Dialect for Oracle:
- org.hibernate.dialect.Oracle10gDialect (Oracle 10g &11g)
- org.hibernate.dialect.Oracle12cDialect
Dialect for SQL Server:
- org.hibernate.dialect.SQLServerDialect
- org.hibernate.dialect.SQLServer2012Dialect
- org.hibernate.dialect.SQLServer2008Dialect
Dialect for MySQL:
- org.hibernate.dialect.MySQLDialect
- org.hibernate.dialect.MySQL5Dialect
Note: org.hibernate.dialect.Oracle10gDialect be used for both Oracle 10g, 11g, 12c.
What is Dialect?
Dialect is a class showing Hibernate the way to convert the data types of Database to the data type of Java and vice versa. Also, it is used to define the way that converts the functions of HSQL (Hibernate SQL) to the functions of Database.
Java SQL Type | Oracle | My SQL | SQL Server |
Types.BIT | number(1,0) | bit | bit |
Types.BIGINT | number(19,0) | bigint | bigint |
Types.DATE | date | date | date |
....... | |||
Types.CLOB | clob | longtext | varchar(MAX) |
Types.BLOB | blob | longblob | varbinary(MAX) |
5. SessionFactory
HibernateUtils is a utility class, it has a method to return the SessionFactory object. This class will be used frequently in examples.
HibernateUtils.java
package org.o7planning.tutorial.hibernate;
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 HibernateUtils {
private static final SessionFactory sessionFactory = buildSessionFactory();
// Hibernate 5:
private static SessionFactory buildSessionFactory() {
try {
// Create the ServiceRegistry from hibernate.cfg.xml
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()//
.configure("hibernate.cfg.xml").build();
// Create a metadata sources using the specified service registry.
Metadata metadata = new MetadataSources(serviceRegistry).getMetadataBuilder().build();
return metadata.getSessionFactoryBuilder().build();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}
6. Hibernate Query Language (HQL)
Hibernate using Hibernate Query Language (HQL) to query data. HQL is a little bit different from SQL you have known before.
SQL:
- Query on the Tables.
HQL:
- Query on the Entity classes.
-- SQL
-- This is a SQL query in table DEPARTMENT.
Select d.DEPT_NO, d.DEPT_NAME from DEPARTMENT d;
-- HQL
-- This is a HQL query in Entity Department.
Select d.deptNo, d.deptName from Department d;
-- Query Object
Select d from Department d;
The rules of operation of Hibernate:
Your application writes HQL. During the operation, Hibernate by itself is aware of the Database type it works with, and it automatically converts HQL into equivalent SQLs to DB types. In fact, we know that there are some differences of SQL syntax among various Database types.
You can reference HQL syntax at:
7. Query data with Hibernate
There are many ways to query data in Hibernate. In this part, I will introduce some typical ways to query data.
Query Object using HQL
The first example, using HQL to query objects (Entity):
QueryObjectDemo.java
package org.o7planning.tutorial.hibernate.query;
import java.util.List;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class QueryObjectDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
try {
// All the action with DB via Hibernate
// must be located in one transaction.
// Start Transaction.
session.getTransaction().begin();
// Create an HQL statement, query the object.
// Equivalent to the SQL statement:
// Select e.* from EMPLOYEE e order by e.EMP_NAME, e.EMP_NO
String sql = "Select e from " + Employee.class.getName() + " e "
+ " order by e.empName, e.empNo ";
// Create Query object.
Query<Employee> query = session.createQuery(sql);
// Execute query.
List<Employee> employees = query.getResultList();
for (Employee emp : employees) {
System.out.println("Emp: " + emp.getEmpNo() + " : "
+ emp.getEmpName());
}
// Commit data.
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
// Rollback in case of an error occurred.
session.getTransaction().rollback();
}
}
}
Results of running the example:
Demo2:
QueryObjectDemo2.java
package org.o7planning.tutorial.hibernate.query;
import java.util.List;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class QueryObjectDemo2 {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
try {
// All the action with DB via Hibernate
// must be located in one transaction
// Start Transaction.
session.getTransaction().begin();
// Create an HQL statement, query the object.
// HQL with parameters.
// Equivalent to the SQL statement:
// Select e.* from EMPLOYEE e cross join DEPARTMENT d
// where e.DEPT_ID = d.DEPT_ID and d.DEPT_NO = :deptNo;
String sql = "Select e from " + Employee.class.getName() + " e "
+ " where e.department.deptNo=:deptNo ";
// Create query object.
Query<Employee> query = session.createQuery(sql);
query.setParameter("deptNo", "D10");
// Execute query.
List<Employee> employees = query.getResultList();
for (Employee emp : employees) {
System.out.println("Emp: " + emp.getEmpNo() + " : "
+ emp.getEmpName());
}
// Commit data
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
// Rollback in case of an error occurred.
session.getTransaction().rollback();
}
}
}
Query a few columns using HQL
QuerySomeColumnDemo.java
package org.o7planning.tutorial.hibernate.query;
import java.util.List;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class QuerySomeColumnDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
try {
session.getTransaction().begin();
// Query some columns.
String sql = "Select e.empId, e.empNo, e.empName from "
+ Employee.class.getName() + " e ";
Query<Object[]> query = session.createQuery(sql);
// Execute Query.
// Get the array of Object
List<Object[]> datas = query.getResultList();
for (Object[] emp : datas) {
System.out.println("Emp Id: " + emp[0]);
System.out.println(" Emp No: " + emp[1]);
System.out.println(" Emp Name: " + emp[2]);
}
// Commit data.
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
// Rollback in case of an error occurred.
session.getTransaction().rollback();
}
}
}
Results of running the example:
Query a few columns using HQL & JavaBean
In the case, if you need to extract the data in some columns of some tables, the best way will be to use Java beans. Java bean class will have a constructor helping set up values in its different fields. This constructor participates in HQL query.
ShortEmpInfo.java
package org.o7planning.tutorial.hibernate.beans;
public class ShortEmpInfo {
private Long empId;
private String empNo;
private String empName;
//
// Constructor have 3 parameters, will be used in the Hibernate Query.
//
public ShortEmpInfo(Long empId, String empNo, String empName) {
this.empId = empId;
this.empNo = empNo;
this.empName = empName;
}
public Long getEmpId() {
return empId;
}
public void setEmpId(Long empId) {
this.empId = empId;
}
public String getEmpNo() {
return empNo;
}
public void setEmpNo(String empNo) {
this.empNo = empNo;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
}
ShortEmpInfoQueryDemo.java
package org.o7planning.tutorial.hibernate.query;
import java.util.List;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.beans.ShortEmpInfo;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class ShortEmpInfoQueryDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
try {
session.getTransaction().begin();
// Using constructor of ShortEmpInfo
String sql = "Select new " + ShortEmpInfo.class.getName()
+ "(e.empId, e.empNo, e.empName)" + " from "
+ Employee.class.getName() + " e ";
Query<ShortEmpInfo> query = session.createQuery(sql);
// Execute query.
// Get a List of ShortEmpInfo
List<ShortEmpInfo> employees = query.getResultList();
for (ShortEmpInfo emp : employees) {
System.out.println("Emp: " + emp.getEmpNo() + " : "
+ emp.getEmpName());
}
// Commit data.
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
// Rollback in case of an error occurred.
session.getTransaction().rollback();
}
}
}
Query retrieves unique result
UniqueResultDemo.java
package org.o7planning.tutorial.hibernate.query;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Department;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class UniqueResultDemo {
public static Department getDepartment(Session session, String deptNo) {
String sql = "Select d from " + Department.class.getName() + " d "//
+ " where d.deptNo= :deptNo ";
Query<Department> query = session.createQuery(sql);
query.setParameter("deptNo", deptNo);
return (Department) query.getSingleResult();
}
public static Employee getEmployee(Session session, Long empId) {
String sql = "Select e from " + Employee.class.getName() + " e "//
+ " where e.empId= :empId ";
Query<Employee> query = session.createQuery(sql);
query.setParameter("empId", empId);
return (Employee) query.getSingleResult();
}
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
try {
session.getTransaction().begin();
Department dept = getDepartment(session, "D10");
Set<Employee> emps = dept.getEmployees();
System.out.println("Dept Name: " + dept.getDeptName());
for (Employee emp : emps) {
System.out.println(" Emp name: " + emp.getEmpName());
}
Employee emp = getEmployee(session, 7839L);
System.out.println("Emp Name: " + emp.getEmpName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
8. Transient, Persistent and Detached
DataUtils.java
package org.o7planning.tutorial.hibernate;
import org.hibernate.Session;
import org.hibernate.query.Query;
import org.o7planning.tutorial.hibernate.entities.Department;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class DataUtils {
public static Department findDepartment(Session session, String deptNo) {
String sql = "Select d from " + Department.class.getName() + " d "//
+ " Where d.deptNo = :deptNo";
Query<Department> query = session.createQuery(sql);
query.setParameter("deptNo", deptNo);
return query.getSingleResult();
}
public static Long getMaxEmpId(Session session) {
String sql = "Select max(e.empId) from " + Employee.class.getName() + " e ";
Query<Number> query = session.createQuery(sql);
Number value = query.getSingleResult();
if (value == null) {
return 0L;
}
return value.longValue();
}
public static Employee findEmployee(Session session, String empNo) {
String sql = "Select e from " + Employee.class.getName() + " e "//
+ " Where e.empNo = :empNo";
Query<Employee> query = session.createQuery(sql);
query.setParameter("empNo", empNo);
return query.getSingleResult();
}
}
This is a simple example using Session.persist (Object) to insert Transient object into the DB. The concept of object Transitent, Persistent, Detached will be explained in this example.
PersistDemo.java
package org.o7planning.tutorial.hibernate.demo;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Department;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class PersistDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Department department = null;
Employee emp = null;
try {
session.getTransaction().begin();
Long maxEmpId = DataUtils.getMaxEmpId(session);
Long empId = maxEmpId + 1;
// Get Persistent object.
department = DataUtils.findDepartment(session, "D10");
// Create transient object
emp = new Employee();
emp.setEmpId(empId);
emp.setEmpNo("E" + empId);
emp.setEmpName("Name " + empId);
emp.setJob("Coder");
emp.setSalary(1000f);
emp.setManager(null);
emp.setHideDate(new Date());
emp.setDepartment(department);
// Using persist(..)
// Now 'emp' is managed by Hibernate.
// it has Persistent status.
// No action at this time with DB.
session.persist(emp);
// At this step the data is pushed to the DB.
// Execute Insert statement.
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
// After the session is closed (commit, rollback, close)
// Objects 'emp', 'dept' became the Detached objects.
// It is no longer in the control of the session.
System.out.println("Emp No: " + emp.getEmpNo());
}
}
Results of running the example:
9. Hibernate Lifecycle
Class Session of Hibernate possess some important methods that are divided into groups as the following illustration:
An object in Hibernate exist in one of four states:
- Transient
- Persistent
- Removed
- Detached
We explain these states with the following illustration:
Transient:
If you create a new java object from an Entity, that object will have a state of Transient. Hibernate does not know about its existence. It is not managed by Hibernate.
Persistent
In case you retrieve Entity objects through methods: get, load, find, getSingleResult,... you get an object that corresponds to a record under the database. This object has a Persistent state. It is managed by Hibernate.
Transient -> Persistent
The Session calls one of the methods: save, saveOrUpdate, persist, merge will push the Transient object into Hibernate management and this object changes to Persistent state. It is equivalent to the update or insert action under Database.
Persistent -> Detached
The Session object calls the method: evict(..) or clear() to expel objects with Persistent state from Hibernate management, now these objects will have a new state called Detached. If it is not Re-Attached, it will be removed by the Java Garbage Gollector according to the normal mechanism.
Detached -> Persistent
Using one of the methods: update(..), saveOrUpdate(..), merge(..) will take an object with Detached state into Hibernate's management. It is equivalent to the update or insert action under Database. The object will switch to Persistent state.
Persistent -> Removed
The Session object calls methods: remove(..), delete(..) to delete an Object (Record). Persistent object will switch to the Removed state.
10. Insert, Update, Delete with Hibernate
Persistent
PersistentDemo.java
package org.o7planning.tutorial.hibernate.demo;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Department;
public class PersistentDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Department department = null;
try {
session.getTransaction().begin();
System.out.println("- Finding Department deptNo = D10...");
// Persistent object.
department = DataUtils.findDepartment(session, "D10");
System.out.println("- First change Location");
// Changing something on Persistent object.
department.setLocation("Chicago " + System.currentTimeMillis());
System.out.println("- Location = " + department.getLocation());
System.out.println("- Calling flush...");
// Use session.flush () to actively push the changes to the DB.
// It works for all changed Persistent objects.
session.flush();
System.out.println("- Flush OK");
System.out.println("- Second change Location");
// Change something on Persistent object
department.setLocation("Chicago " + System.currentTimeMillis());
// Print out location
System.out.println("- Location = " + department.getLocation());
System.out.println("- Calling commit...");
// Commit
session.getTransaction().commit();
System.out.println("- Commit OK");
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
// Create the session after it had been closed earlier
// (Cause by commit or update)
session = factory.getCurrentSession();
try {
session.getTransaction().begin();
System.out.println("- Finding Department deptNo = D10...");
// Query lại Department D10.
department = DataUtils.findDepartment(session, "D10");
// Print out location
System.out.println("- D10 Location = " + department.getLocation());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
Results of running the example:
Transient --> Persistent : Overview
Transient --> Persistent : Using persist(Object)
PersistTransientDemo.java
package org.o7planning.tutorial.hibernate.demo;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
import org.o7planning.tutorial.hibernate.entities.Timekeeper;
public class PersistTransientDemo {
private static DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
private static Timekeeper persist_Transient(Session session, Employee emp) {
// Note:
// Configuring of timekeeperId
// @GeneratedValue(generator = "uuid")
// @GenericGenerator(name = "uuid", strategy = "uuid2")
Timekeeper tk1 = new Timekeeper();
tk1.setEmployee(emp);
tk1.setInOut(Timekeeper.IN);
tk1.setDateTime(new Date());
// Now, 'tk1' is transient object
System.out.println("- tk1 Persistent? " + session.contains(tk1));
System.out.println("====== CALL persist(tk).... ===========");
// Hibernate assign value to Id of 'tk1'
// No action to DB.
session.persist(tk1);
System.out
.println("- tk1.getTimekeeperId() = " + tk1.getTimekeeperId());
// Now 'tk1' is Persistent object.
// But no action with DB.
// ==> true
System.out.println("- tk1 Persistent? " + session.contains(tk1));
System.out.println("- Call flush..");
// Flush data to DB.
// Hibernate execute insert statement.
session.flush();
String timekeeperId = tk1.getTimekeeperId();
System.out.println("- timekeeperId = " + timekeeperId);
System.out.println("- inOut = " + tk1.getInOut());
System.out.println("- dateTime = " + df.format(tk1.getDateTime()));
System.out.println();
return tk1;
}
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
try {
session.getTransaction().begin();
emp = DataUtils.findEmployee(session, "E7499");
persist_Transient(session, emp);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
Results of running the example:
Transient --> Persistent : Using save(Object)
SaveTransientDemo.java
package org.o7planning.tutorial.hibernate.demo;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
import org.o7planning.tutorial.hibernate.entities.Timekeeper;
public class SaveTransientDemo {
private static DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
private static Timekeeper persist_Transient(Session session, Employee emp) {
// See configuration of timekeeperId:
// @GeneratedValue(generator = "uuid")
// @GenericGenerator(name = "uuid", strategy = "uuid2")
// Create an Object, Transitent state.
Timekeeper tk2 = new Timekeeper();
tk2.setEmployee(emp);
tk2.setInOut(Timekeeper.IN);
tk2.setDateTime(new Date());
// Now 'tk3' are state Transient.
System.out.println("- tk2 Persistent? " + session.contains(tk2));
System.out.println("====== CALL save(tk).... ===========");
// save() very similar to persist()
// save() return ID, persist() return void.
// Hibernate assign ID value to 'tk2', no action with DB
// And return ID of 'tk2'.
Serializable id = session.save(tk2);
System.out.println("- id = " + id);
//
System.out
.println("- tk2.getTimekeeperId() = " + tk2.getTimekeeperId());
// Now, 'tk2' has Persistent state
// It has been managed in Session.
// ==> true
System.out.println("- tk2 Persistent? " + session.contains(tk2));
System.out.println("- Call flush..");
// To push data into the DB, call flush().
// If not call flush() data will be pushed to the DB when calling commit().
// Will execute insert statement.
session.flush();
String timekeeperId = tk2.getTimekeeperId();
System.out.println("- timekeeperId = " + timekeeperId);
System.out.println("- inOut = " + tk2.getInOut());
System.out.println("- dateTime = " + df.format(tk2.getDateTime()));
System.out.println();
return tk2;
}
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
try {
session.getTransaction().begin();
emp = DataUtils.findEmployee(session, "E7499");
persist_Transient(session, emp);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
Results of running the example:
Transient --> Persistent : Using saveOrUpdate(Object)
SaveOrUpdateTransientDemo.java
package org.o7planning.tutorial.hibernate.demo;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
import org.o7planning.tutorial.hibernate.entities.Timekeeper;
public class SaveOrUpdateTransientDemo {
private static DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
private static Timekeeper saveOrUpdate_Transient(Session session,
Employee emp) {
// See configuration of timekeeperId:
// @GeneratedValue(generator = "uuid")
// @GenericGenerator(name = "uuid", strategy = "uuid2")
// Create an Object, Transitent state.
Timekeeper tk3 = new Timekeeper();
tk3.setEmployee(emp);
tk3.setInOut(Timekeeper.IN);
tk3.setDateTime(new Date());
// Now 'tk3' are state Transient.
System.out.println("- tk3 Persistent? " + session.contains(tk3));
System.out.println("====== CALL saveOrUpdate(tk).... ===========");
// Here Hibernate checks, 'tk3' have ID or not (timekeeperId)
// If no, it will be assigned automatically
session.saveOrUpdate(tk3);
System.out
.println("- tk3.getTimekeeperId() = " + tk3.getTimekeeperId());
// Now 'tk3' has Persistent state
// It has been managed in Session.
// But no action insert, or update to DB.
// ==> true
System.out.println("- tk3 Persistent? " + session.contains(tk3));
System.out.println("- Call flush..");
// To push data into the DB, call flush().
// If not call flush() data will be pushed to the DB when calling commit().
// Now possible to Insert or Update DB. (!!!)
// Depending on the ID of 'tk3' exists in the DB or not
session.flush();
String timekeeperId = tk3.getTimekeeperId();
System.out.println("- timekeeperId = " + timekeeperId);
System.out.println("- inOut = " + tk3.getInOut());
System.out.println("- dateTime = " + df.format(tk3.getDateTime()));
System.out.println();
return tk3;
}
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
try {
session.getTransaction().begin();
emp = DataUtils.findEmployee(session, "E7499");
saveOrUpdate_Transient(session, emp);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
Results of running the example:
Transient --> Persistent : Using merge(Object)
MergeTransientDemo.java
package org.o7planning.tutorial.hibernate.demo;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
import org.o7planning.tutorial.hibernate.entities.Timekeeper;
public class MergeTransientDemo {
private static DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
private static Timekeeper saveOrUpdate_Transient(Session session,
Employee emp) {
// Note:
// Configuring of timekeeperId
// @GeneratedValue(generator = "uuid")
// @GenericGenerator(name = "uuid", strategy = "uuid2")
Timekeeper tk4 = new Timekeeper();
tk4.setEmployee(emp);
tk4.setInOut(Timekeeper.IN);
tk4.setDateTime(new Date());
// Now 'tk4' Transient status.
System.out.println("- tk4 Persistent? " + session.contains(tk4));
System.out.println("====== CALL merge(tk).... ===========");
// Hibernate2 has method saveOrUpdateCopy
// Hibernate3 change saveOrUpdateCopy to merge
// So there will be similarities between the two methods merge and copyOrUpdate
// Here Hibernate check tk4 has ID or not
// If not, Hibernate assign value to ID of tk4
// Return copy of tk4.
Timekeeper tk4Copy = (Timekeeper) session.merge(tk4);
System.out
.println("- tk4.getTimekeeperId() = " + tk4.getTimekeeperId());
// Now 'tk4' still Transient state.
// and 'tk4Copy' has Persistent status
// No action with DB (insert or update).
System.out.println("- tk4 Persistent? " + session.contains(tk4));
// 'tk4Copy' has Persistent status
// ==> true
System.out
.println("- tk4Copy Persistent? " + session.contains(tk4Copy));
System.out.println("- Call flush..");
// This time have Insert or Update to DB. (!!!)
session.flush();
// 'tk4' still Transitent, after flush().
// merge(..) safer than saveOrUpdate().
System.out.println("- tk4 Persistent? " + session.contains(tk4));
//
String timekeeperId = tk4.getTimekeeperId();
System.out.println("- timekeeperId = " + timekeeperId);
System.out.println("- inOut = " + tk4.getInOut());
System.out.println("- dateTime = " + df.format(tk4.getDateTime()));
System.out.println();
return tk4;
}
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
try {
session.getTransaction().begin();
emp = DataUtils.findEmployee(session, "E7499");
saveOrUpdate_Transient(session, emp);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
Results of running the example:
Persistent --> Detached
An object with Persistent state (Managed by Hibernate) can swith to Detached state (not managed by Hibernate) through the following method of Session:
- evict(Object)
Evict an object out of Hibernate's management
- clear()
Evict all the objects out of Hibernate's management.
Note: When the Session call object is one of the methods: commit(), close(), rollback(), this session will end. All Persistence objects of this session will be considered Detached for a new session.
EvictDemo.java
package org.o7planning.tutorial.hibernate.demo;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class EvictDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
try {
session.getTransaction().begin();
// This is object has Persistent status
emp = DataUtils.findEmployee(session, "E7499");
// ==> true
System.out.println("- emp Persistent? " + session.contains(emp));
// using evict() to evicts a single object from the session
session.evict(emp);
// Now 'emp' has Detached status
// ==> false
System.out.println("- emp Persistent? " + session.contains(emp));
// All change on the 'emp' will not update
// if not reatach 'emp' to session
emp.setEmpNo("NEW");
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
Results of running the example:
ClearDemo.java
package org.o7planning.tutorial.hibernate.demo;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Department;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class ClearDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session = factory.getCurrentSession();
Employee emp = null;
Department dept = null;
try {
session.getTransaction().begin();
// It is an object has Persistent status.
emp = DataUtils.findEmployee(session, "E7499");
dept = DataUtils.findDepartment(session, "D10");
// clear() evicts all the objects in the session.
session.clear();
// Now 'emp' & 'dept' has Detached status
// ==> false
System.out.println("- emp Persistent? " + session.contains(emp));
System.out.println("- dept Persistent? " + session.contains(dept));
// All change on the 'emp' will not update
// if not reatach 'emp' to session
emp.setEmpNo("NEW");
dept = DataUtils.findDepartment(session, "D20");
System.out.println("Dept Name = "+ dept.getDeptName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
Results of running the example:
Detached --> Persistent : Overview
An object with Detached state (detached from the management of Hibernate) can be re-attached via several methods of the Session:
- update(Object)
- saveOrUpdate(Object)
- merge(Object)
- refresh(Object)
- lock(Object)
You can see the difference among methods in the following examples:
Detached --> Persistent : Using update(Object)
UpdateDetachedDemo.java
package org.o7planning.tutorial.hibernate.demo;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class UpdateDetachedDemo {
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session1 = factory.getCurrentSession();
Employee emp = null;
try {
session1.getTransaction().begin();
// This is a Persistent object.
emp = DataUtils.findEmployee(session1, "E7499");
// session1 was closed after a commit is called.
session1.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session1.getTransaction().rollback();
}
// Open other session
Session session2 = factory.getCurrentSession();
try {
session2.getTransaction().begin();
// Check state of 'emp'
// ==> false
System.out.println("- emp Persistent? " + session2.contains(emp));
System.out.println("Emp salary: " + emp.getSalary());
emp.setSalary(emp.getSalary() + 100);
// update (..) is only used for Detached object.
// (Not for Transient object).
// Use the update (emp) to bring back emp Persistent state.
session2.update(emp);
// Call flush
// Update statement will be called.
session2.flush();
System.out.println("Emp salary after update: " + emp.getSalary());
// session2 was closed after a commit is called.
session2.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session2.getTransaction().rollback();
}
}
}
Results of running the example:
Detached --> Persistent : Using saveOrUpdate(Object)
SaveOrUpdateDetachedDemo.java
package org.o7planning.tutorial.hibernate.demo;
import java.util.Random;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class SaveOrUpdateDetachedDemo {
public static void main(String[] args) {
// An object Detached state.
Employee emp = getEmployee_Detached();
System.out.println(" - GET EMP " + emp.getEmpId());
// Random delete or not delete Employee
boolean delete = deleteOrNotDelete(emp.getEmpId());
System.out.println(" - DELETE? " + delete);
// Call saveOrUpdate for detached object.
saveOrUpdate_test(emp);
// After call saveOrUpdate()
System.out.println(" - EMP ID " + emp.getEmpId());
}
// Return Employee object has Detached state
private static Employee getEmployee_Detached() {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session1 = factory.getCurrentSession();
Employee emp = null;
try {
session1.getTransaction().begin();
Long maxEmpId = DataUtils.getMaxEmpId(session1);
System.out.println(" - Max Emp ID " + maxEmpId);
Employee emp2 = DataUtils.findEmployee(session1, "E7839");
Long empId = maxEmpId + 1;
emp = new Employee();
emp.setEmpId(empId);
emp.setEmpNo("E" + empId);
emp.setDepartment(emp2.getDepartment());
emp.setEmpName(emp2.getEmpName());
emp.setHideDate(emp2.getHideDate());
emp.setJob("Test");
emp.setSalary(1000F);
// emp has been managed by Hibernate
session1.persist(emp);
// session1 was closed after a commit is called.
// An Employee record are insert into DB.
session1.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session1.getTransaction().rollback();
}
// Session1 closed 'emp' switch to Detached state.
return emp;
}
// Random: delete or not delete.
private static boolean deleteOrNotDelete(Long empId) {
// A random number 0-9
int random = new Random().nextInt(10);
if (random < 5) {
return false;
}
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session2 = factory.getCurrentSession();
try {
session2.getTransaction().begin();
String sql = "Delete " + Employee.class.getName() + " e "
+ " where e.empId =:empId ";
Query query = session2.createQuery(sql);
query.setParameter("empId", empId);
query.executeUpdate();
session2.getTransaction().commit();
return true;
} catch (Exception e) {
e.printStackTrace();
session2.getTransaction().rollback();
return false;
}
}
private static void saveOrUpdate_test(Employee emp) {
SessionFactory factory = HibernateUtils.getSessionFactory();
// Open other session
Session session3 = factory.getCurrentSession();
try {
session3.getTransaction().begin();
// Check state of emp
// ==> false
System.out.println(" - emp Persistent? " + session3.contains(emp));
System.out.println(" - Emp salary before update: "
+ emp.getSalary());
// Set new salary for Detached emp object.
emp.setSalary(emp.getSalary() + 100);
// Using saveOrUpdate(emp) to switch emp to Persistent state
// Note: If exists object same ID in session, this method raise Exception
//
// Now, no action with DB.
session3.saveOrUpdate(emp);
// By pushing data into the DB.
// It will call a Insert or update statement.
// If the record is deleted before ==> insert
// Else ==> update.
session3.flush();
System.out
.println(" - Emp salary after update: " + emp.getSalary());
// session3 was closed after a commit is called.
session3.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session3.getTransaction().rollback();
}
}
}
Run the above example a few times, you can see two situations, saveOrUpdate creates actions: Insert or Update to Database.
INSERT:
UPDATE:
Detached --> Persistent : Using merge(Object)
Hibernate version 2 has saveOrUpdateCopy(Object) method. From the version 3 onwards, it is renamed merge(Object). Thus, merge has some similarity and difference compared with saveOrUpdate.merge(Object) does not put object under the management of Hibernate, but it create a copy of the object and manage the copy object instead.If you call saveOrUpdate(aObject) while bObject is being managed by Hibernate and has the same ID with aObject, an exception will be thrown out, when you use the merge(aObject) not get this Exception.
MergeDetachedDemo.java
package org.o7planning.tutorial.hibernate.demo;
import java.util.Random;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class MergeDetachedDemo {
public static void main(String[] args) {
// An object has Detached status
Employee emp = getEmployee_Detached();
System.out.println(" - GET EMP " + emp.getEmpId());
// Random: delete or not delete the Employee by ID.
boolean delete = deleteOrNotDelete(emp.getEmpId());
System.out.println(" - DELETE? " + delete);
// Call saveOrUpdate Detached object
saveOrUpdate_test(emp);
// After call saveOrUpdate
// ...
System.out.println(" - EMP ID " + emp.getEmpId());
}
// Method return Employee object
// and has Detached status.
private static Employee getEmployee_Detached() {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session1 = factory.getCurrentSession();
Employee emp = null;
try {
session1.getTransaction().begin();
Long maxEmpId = DataUtils.getMaxEmpId(session1);
System.out.println(" - Max Emp ID " + maxEmpId);
Employee emp2 = DataUtils.findEmployee(session1, "E7839");
Long empId = maxEmpId + 1;
emp = new Employee();
emp.setEmpId(empId);
emp.setEmpNo("E" + empId);
emp.setDepartment(emp2.getDepartment());
emp.setEmpName(emp2.getEmpName());
emp.setHideDate(emp2.getHideDate());
emp.setJob("Test");
emp.setSalary(1000F);
// 'emp' has Persistant state
session1.persist(emp);
// session1 was closed after a commit is called.
// An Employee record are insert into DB.
session1.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session1.getTransaction().rollback();
}
// session1 closed, 'emp' switched Detached state.
return emp;
}
// Delete Employee by ID
// Random: delete or not delete
private static boolean deleteOrNotDelete(Long empId) {
// A random number 0-9
int random = new Random().nextInt(10);
if (random < 5) {
return false;
}
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session2 = factory.getCurrentSession();
try {
session2.getTransaction().begin();
String sql = "Delete " + Employee.class.getName() + " e "
+ " where e.empId =:empId ";
Query query = session2.createQuery(sql);
query.setParameter("empId", empId);
query.executeUpdate();
session2.getTransaction().commit();
return true;
} catch (Exception e) {
e.printStackTrace();
session2.getTransaction().rollback();
return false;
}
}
private static void saveOrUpdate_test(Employee emp) {
SessionFactory factory = HibernateUtils.getSessionFactory();
// Open other session
Session session3 = factory.getCurrentSession();
try {
session3.getTransaction().begin();
// The fact, 'emp' has Detached state
// It is not managed by Hibernate.
// Check the status of emp:
// ==> false
System.out.println(" - emp Persistent? " + session3.contains(emp));
System.out.println(" - Emp salary before update: "
+ emp.getSalary());
// Set new salary for Detached object 'emp'
emp.setSalary(emp.getSalary() + 100);
// merge(emp) return empMerge, a copy of 'emp',
// empMerge managed by Hibernate
// 'emp' still in Detached state
//
// At this time there is no action regarding DB.
Employee empMerge = (Employee) session3.merge(emp);
// ==> false
System.out.println(" - emp Persistent? " + session3.contains(emp));
// ==> true
System.out.println(" - empMerge Persistent? "
+ session3.contains(empMerge));
// Push data into the DB.
// Here it is possible to create the Insert or Update on DB.
// If the corresponding record has been deleted by someone, it insert
// else it update
session3.flush();
System.out
.println(" - Emp salary after update: " + emp.getSalary());
// session3 closed after a commit is called.
session3.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session3.getTransaction().rollback();
}
}
}
Results of running the example:
INSERT:
UPDATE:
Detached --> Persistent : Using refresh(Object)
RefreshDetachedDemo.java
package org.o7planning.tutorial.hibernate.demo;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.o7planning.tutorial.hibernate.DataUtils;
import org.o7planning.tutorial.hibernate.HibernateUtils;
import org.o7planning.tutorial.hibernate.entities.Employee;
public class RefreshDetachedDemo {
public static void main(String[] args) {
// an Object with Detached status
Employee emp = getEmployee_Detached();
System.out.println(" - GET EMP " + emp.getEmpId());
// Refresh Object
refresh_test(emp);
}
// Return Employee object has Detached state
private static Employee getEmployee_Detached() {
SessionFactory factory = HibernateUtils.getSessionFactory();
Session session1 = factory.getCurrentSession();
Employee emp = null;
try {
session1.getTransaction().begin();
emp = DataUtils.findEmployee(session1, "E7839");
// session1 was closed after a commit is called.
// An Employee record are insert into DB.
session1.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session1.getTransaction().rollback();
}
// Session1 closed 'emp' switch to Detached state.
return emp;
}
private static void refresh_test(Employee emp) {
SessionFactory factory = HibernateUtils.getSessionFactory();
// Open other session
Session session2 = factory.getCurrentSession();
try {
session2.getTransaction().begin();
// Check the status of 'emp' (Detached)
// ==> false
System.out.println(" - emp Persistent? " + session2.contains(emp));
System.out.println(" - Emp salary before update: "
+ emp.getSalary());
// Set new salary for 'emp'.
emp.setSalary(emp.getSalary() + 100);
// refresh: make a query statement
// and switch 'emp' to Persistent state
// The changes are ignored
session2.refresh(emp);
// ==> true
System.out.println(" - emp Persistent? " + session2.contains(emp));
System.out.println(" - Emp salary after refresh: "
+ emp.getSalary());
session2.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session2.getTransaction().rollback();
}
}
}
Results of running the example:
Detached --> Persistent : Using lock(Object)
- TODO...