Hibernate by JavaScaler
Hibernate by JavaScaler
Hibernate by JavaScaler
Author: Md Kashif Ali
Copyright © 2024 by Md Kashif Ali
All rights reserved.
Copyright Notice
This book, Hibernate by JavaScaler, and all the content, including text, illustrations,
examples, code, and diagrams, are the exclusive intellectual property of Md Kashif Ali. No
part of this book may be reproduced, stored, or transmitted in any form or by any means,
electronic, mechanical, photocopying, recording, or otherwise, without prior written
permission from the author.
Disclaimer
This book is provided “as is,” with no guarantees or warranties, either express or implied.
While every effort has been made to ensure the accuracy, reliability, and completeness of
the information provided, the author and publisher make no representations or warranties
regarding the contents.
The material in this book is intended solely for educational purposes. Although every effort
has been made to ensure its relevance and correctness, Hibernate and associated
technologies are constantly evolving, and certain information might become outdated over
time. Readers are strongly advised to refer to the latest official documentation and adapt the
provided examples accordingly.
The author and publisher assume no responsibility for any consequences, damages, or
losses incurred as a result of using the information or code provided in this book.
Be Advised:
The author reserves the right to take strict legal action against any unauthorized use,
reproduction, or distribution of this book. Proceed wisely.
Contact Information:
For permissions, collaborations, or queries:
● Email: javascaler@gmail.com
● Website: JavaScaler
1. Introduction of Hibernate
3. Hibernate Features
7. Association Mapping
Many-to-Many Mapping
8. Version Mapping
9. Timestamp Mapping
Polymorphic Query
ACID Property
Hibernate 1
Transaction Concurrency Problem & Solutions
Types of Transactions
JDBC Transaction
JTA Transaction
CMT Transaction
Exploring SessionFactory
Object States
Hibernate 2
4. Performance: It includes caching mechanisms that enhance application
performance.
Session
The Session object represents a single unit of work with the database. It is used
to create, read, and delete persistent objects.
Transaction
The Transaction interface is used to manage transactions in Hibernate. It
abstracts the underlying transaction management of the database.
Query
The Query interface allows the execution of HQL (Hibernate Query Language)
or SQL queries against the database.
Criteria
The Criteria API is a more object-oriented way to create and execute queries.
Configuration
Hibernate 3
The Configuration class represents the entire configuration for Hibernate. It is
used to configure the SessionFactory .
2. Hibernate Query Language (HQL): HQL is similar to SQL but works with
Java objects instead of tables.
5. Lazy Loading: Data is fetched on-demand, reducing the initial load time.
Step-by-Step Setup
Hibernate 4
1. Add Hibernate Dependencies
If using Maven, add the following dependencies to your pom.xml :
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.32.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.32.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
Hibernate 5
<property name="hibernate.hbm2ddl.auto">update</pro
perty>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</propert
y>
package com.example.model;
Hibernate 6
<property name="name" column="NAME"/>
<property name="department" column="DEPARTMENT"/>
<property name="salary" column="SALARY"/>
</class>
</hibernate-mapping>
package com.example.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
static {
try {
sessionFactory = new Configuration().configure
().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
package com.example.main;
import com.example.model.Employee;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
Hibernate 7
import org.hibernate.Transaction;
try {
transaction = session.beginTransaction();
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
}
1.6 Summary
Hibernate is a powerful ORM tool that simplifies Java application development
by handling database interactions efficiently. It abstracts complex SQL queries
into high-level Java objects, offers robust transaction management, supports
various types of caching, and provides a rich query language (HQL). Setting up
Hibernate 8
Hibernate involves adding dependencies, configuring the hibernate.cfg.xml file,
creating model classes, and writing mapping files.
By using Hibernate, developers can focus more on business logic rather than
dealing with intricate database operations, leading to more maintainable and
scalable applications.
Hibernate 9
Example of JDBC Usage
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
while (resultSet.next()) {
System.out.println("ID: " + resultSet.getIn
t("id"));
System.out.println("Name: " + resultSet.get
String("name"));
System.out.println("Department: " + resultS
et.getString("department"));
System.out.println("Salary: " + resultSet.g
etDouble("salary"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Hibernate 10
2.3 Overview of Hibernate
What is Hibernate?
Hibernate is an open-source ORM (Object-Relational Mapping) framework for
Java. It simplifies database interactions by mapping Java classes to database
tables. Hibernate abstracts the underlying SQL, allowing developers to work
with high-level Java objects.
package com.example;
import org.hibernate.Session;
import org.hibernate.Transaction;
Hibernate 11
Transaction transaction = null;
try {
transaction = session.beginTransaction();
session.save(employee);
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
}
Hibernate 12
First-level and second-level
Caching No built-in caching
caching
When you need fine-grained control over SQL and database operations.
When you want to leverage ORM features like caching, lazy loading, and
automatic table creation.
2.7 Summary
JDBC and Hibernate are both powerful tools for database interaction in Java
applications, each with its own strengths and use cases. JDBC offers low-level
control and is suitable for simple applications and scenarios requiring direct
Hibernate 13
SQL management. Hibernate, on the other hand, provides a high-level
abstraction that simplifies database operations through ORM, making it ideal for
complex and large-scale applications.
Understanding the differences between JDBC and Hibernate helps developers
choose the right tool for their specific needs, balancing control, simplicity,
performance, and maintainability.
Example:
Hibernate 14
query.setParameter("salary", 50000);
List<Employee> results = query.list();
<property name="hibernate.hbm2ddl.auto">update</property>
3.2.5 Caching
Hibernate supports both first-level (Session) and second-level
(SessionFactory) caching to improve performance by reducing database
access.
Hibernate 15
Infinispan.
<property name="hibernate.cache.use_second_level_cache">tru
e</property>
<property name="hibernate.cache.region.factory_class">org.h
ibernate.cache.ehcache.EhCacheRegionFactory</property>
Eager Loading: Associated entities are loaded immediately with the parent
entity.
Example:
@Entity
public class Department {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "departme
nt")
private Set<Employee> employees;
}
Example:
Hibernate 16
throw e;
}
session.beginTransaction();
Employee employee = session.get(Employee.class, 1);
employee.setSalary(60000);
session.getTransaction().commit();
One-to-Many Association:
@Entity
public class Department {
@OneToMany(mappedBy = "department")
private Set<Employee> employees;
}
@Entity
public class Employee {
@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
}
Inheritance Mapping:
Hibernate 17
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Person {
@Id
private int id;
private String name;
}
@Entity
public class Employee extends Person {
private double salary;
}
HQL Query:
3.3 Summary
Hibernate 18
Hibernate offers a rich set of features that simplify database interactions,
enhance performance, and improve maintainability. Key features like ORM,
HQL, Criteria API, automatic table creation, caching, lazy and eager loading,
transaction management, automatic dirty checking, association and inheritance
mapping, and support for HQL and native SQL queries make Hibernate a
powerful framework for enterprise-level applications. By leveraging these
features, developers can build robust, scalable, and efficient applications with
ease.
4.2 Prerequisites
Before starting, ensure you have the following installed:
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
Hibernate 19
<artifactId>hibernate-core</artifactId>
<version>5.4.32.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.32.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
</dependencies>
Hibernate 20
y>
package com.example.model;
Hibernate 21
return department;
}
Hibernate 22
Create a utility class to initialize Hibernate and provide the SessionFactory . Save
it in the src/main/java/com/example/util directory:
package com.example.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
static {
try {
sessionFactory = new Configuration().configure
().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
package com.example.main;
import com.example.model.Employee;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
Hibernate 23
Session session = HibernateUtil.getSessionFactory
().openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
}
4.5 Summary
This chapter demonstrated a simple example of using Hibernate with an hbm.xml
mapping file. We covered setting up the project, creating configuration and
Hibernate 24
mapping files, and performing basic CRUD operations. By following these
steps, you can create and run a Hibernate application that maps Java classes
to database tables, leveraging Hibernate's powerful ORM capabilities.
5.2 Prerequisites
Ensure you have the following installed:
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.32.Final</version>
</dependency>
Hibernate 25
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.32.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
</dependencies>
Hibernate 26
<mapping class="com.example.model.Employee"/>
</session-factory>
</hibernate-configuration>
package com.example.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
Hibernate 27
public String getName() {
return name;
}
package com.example.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
Hibernate 28
static {
try {
sessionFactory = new Configuration().configure
().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
package com.example.main;
import com.example.model.Employee;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
try {
transaction = session.beginTransaction();
Hibernate 29
employee.setSalary(75000);
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
}
class, and you should see Hibernate SQL output in the console, indicating that
the Employee object was successfully saved to the database.
5.5 Summary
This chapter demonstrated how to use annotations with Hibernate to map Java
classes to database tables. We covered setting up the project, creating
configuration files, defining the entity with annotations, and performing basic
CRUD operations. Using annotations simplifies the configuration process and
enhances the readability of the mapping, making it easier to maintain and
manage.
Hibernate 30
Table Per Class Mapping
In this chapter, we will discuss these two strategies in detail and provide
examples for each.
6.1.2 Example
Consider an inheritance hierarchy with a base class Person and two subclasses
Employee and Customer .
package com.example.model;
import javax.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
Hibernate 31
this.id = id;
}
Employee.java
package com.example.model;
import javax.persistence.Entity;
@Entity
public class Employee extends Person {
private String department;
private double salary;
Hibernate 32
}
}
Customer.java
package com.example.model;
import javax.persistence.Entity;
@Entity
public class Customer extends Person {
private String loyaltyLevel;
<mapping class="com.example.model.Person"/>
<mapping class="com.example.model.Employee"/>
<mapping class="com.example.model.Customer"/>
Hibernate 33
package com.example.main;
import com.example.model.Customer;
import com.example.model.Employee;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
try {
transaction = session.beginTransaction();
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
Hibernate 34
} finally {
session.close();
}
}
}
6.2.2 Example
Using the same Person , Employee , and Customer classes as before, we will now
map them using the Table Per Concrete Class strategy.
package com.example.model;
import javax.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
Hibernate 35
private String name;
6.3 Summary
Hibernate 36
This chapter covered two inheritance mapping strategies in Hibernate:
Table Per Class Mapping: Each class in the hierarchy has its own table.
Table Per Concrete Class Mapping: Each concrete class has its own table,
and inherited fields are included in each table.
Many-to-Many Mapping
7.1.2 Example
Consider an example where each Person has one Address .
package com.example.model;
import javax.persistence.*;
@Entity
Hibernate 37
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToOne
@JoinColumn(name = "address_id")
private Address address;
Address.java
Hibernate 38
package com.example.model;
import javax.persistence.*;
@Entity
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String street;
private String city;
Hibernate 39
Step 2: Create Hibernate Configuration
Add the annotated classes to your hibernate.cfg.xml :
<mapping class="com.example.model.Person"/>
<mapping class="com.example.model.Address"/>
package com.example.main;
import com.example.model.Address;
import com.example.model.Person;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
try {
transaction = session.beginTransaction();
Hibernate 40
person.setAddress(address);
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
}
7.2.2 Example
Using the same Person and Address classes, we will now make the association
bi-directional.
Hibernate 41
package com.example.model;
import javax.persistence.*;
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@OneToOne(mappedBy = "person")
private Address address;
Hibernate 42
}
}
Address.java
package com.example.model;
import javax.persistence.*;
@Entity
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String street;
private String city;
@OneToOne
@JoinColumn(name = "person_id")
private Person person;
Hibernate 43
public String getCity() {
return city;
}
package com.example.main;
import com.example.model.Address;
import com.example.model.Person;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
Hibernate 44
try {
transaction = session.beginTransaction();
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
}
Hibernate 45
In a many-to-many mapping, multiple instances of one entity are associated
with multiple instances of another entity. This type of association typically
requires a join table.
7.3.2 Example
Consider an example where Student and Course entities have a many-to-many
relationship.
package com.example.model;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_i
d")
)
private Set<Course> courses = new HashSet<>();
Hibernate 46
public void setId(int id) {
this.id = id;
}
Course.java
package com.example.model;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String title;
@ManyToMany(mappedBy = "courses")
private Set<Student> students = new HashSet<>();
Hibernate 47
// Getters and setters
public int getId() {
return id;
}
}
}
<mapping class="com.example.model.Student"/>
<mapping class="com.example.model.Course"/>
Hibernate 48
package com.example.main;
import com.example.model.Course;
import com.example.model.Student;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
import java.util.HashSet;
import java.util.Set;
try {
transaction = session.beginTransaction();
Hibernate 49
session.save(course2);
session.save(student);
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
}
7.4 Summary
This chapter covered three types of association mappings in Hibernate:
We provided detailed examples and code for each type of mapping. These
mappings enable you to define complex relationships between entities and
leverage Hibernate's ORM capabilities to manage these associations efficiently.
Hibernate 50
Chapter 8: Version Mapping
Version mapping in Hibernate is a technique used to manage concurrent
access to data in a database. It ensures data consistency by using a versioning
mechanism that helps prevent the "lost update" problem, where multiple
transactions simultaneously modify the same data and the last transaction
overwrites the previous changes.
package com.example.model;
import javax.persistence.*;
Hibernate 51
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private double price;
@Version
private int version;
Hibernate 52
}
<mapping class="com.example.model.Product"/>
package com.example.main;
import com.example.model.Product;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
try {
transaction = session.beginTransaction();
// Create a product
Product product = new Product();
product.setName("Laptop");
Hibernate 53
product.setPrice(1500.00);
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
}
8.2.2 Explanation
The Product entity has a @Version field, which Hibernate uses to manage
versioning.
Hibernate 54
When saving or updating a Product , Hibernate automatically checks the
version field to ensure data consistency.
HandlingOptimisticLockException.java
package com.example.main;
import com.example.model.Product;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.exception.LockAcquisitionException;
try {
transaction1 = session1.beginTransaction();
transaction2 = session2.beginTransaction();
Hibernate 55
Product product2 = session2.get(Product.class,
1);
} catch (LockAcquisitionException e) {
if (transaction2 != null) {
transaction2.rollback();
}
System.out.println("Optimistic lock exception:
" + e.getMessage());
} finally {
session1.close();
session2.close();
}
}
}
8.3.1 Explanation
Two sessions are used to simulate concurrent updates.
The first session updates the product and commits the transaction.
another transaction.
8.4 Summary
Hibernate 56
Version mapping is a crucial feature in Hibernate for managing concurrent
access to entities. By using version properties and optimistic locking, Hibernate
ensures data consistency and prevents the "lost update" problem. This chapter
covered the basics of version mapping, provided a step-by-step
implementation example, and demonstrated how to handle
OptimisticLockException . Understanding version mapping helps in building robust
applications that handle concurrent data access effectively.
Data Integrity: Ensuring that the most recent changes are always reflected
in the data.
Hibernate 57
Consider an entity User with createdAt and updatedAt timestamp fields.
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@CreationTimestamp
@Column(updatable = false)
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
Hibernate 58
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDAT
E CURRENT_TIMESTAMP
);
Hibernate 59
transaction.commit();
}
import javax.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Hibernate 60
@CreationTimestamp
@Column(updatable = false)
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
@Version
private int version;
Using the @Version annotation, Hibernate increments the version number with
each update, helping to prevent concurrent update issues.
9.7 Conclusion
Timestamp mapping in Hibernate simplifies the management of creation and
update timestamps within your entities. By leveraging @CreationTimestamp and
@UpdateTimestamp , you can automate this process, ensuring accurate and
consistent timestamp data for auditing and concurrency control.
In the next chapter, we will explore the Data Access Object (DAO) pattern and
how it can be implemented in Hibernate to separate the data persistence logic
from business logic, providing a cleaner and more modular codebase.
Hibernate 61
underlying database details. This separation of concerns helps in managing
and maintaining the codebase more effectively.
Hibernate 62
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.32.Final</version>
</dependency>
<!-- Other dependencies like JPA, MySQL Connector, etc.
-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
</dependencies>
Hibernate 63
ty>
<property name="hibernate.c3p0.timeout">300</proper
ty>
<property name="hibernate.c3p0.max_statements">50</
property>
<property name="hibernate.c3p0.idle_test_period">30
00</property>
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "users")
Hibernate 64
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@CreationTimestamp
@Column(updatable = false)
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
Hibernate 65
import org.hibernate.cfg.Configuration;
import java.util.List;
public UserDaoImpl() {
sessionFactory = new Configuration().configure().bu
ildSessionFactory();
}
@Override
public void save(User user) {
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction
();
session.save(user);
transaction.commit();
session.close();
}
@Override
public User findById(Long id) {
Session session = sessionFactory.openSession();
User user = session.get(User.class, id);
session.close();
return user;
}
@Override
public List<User> findAll() {
Session session = sessionFactory.openSession();
List<User> users = session.createQuery("from User",
User.class).list();
session.close();
return users;
}
Hibernate 66
@Override
public void update(User user) {
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction
();
session.update(user);
transaction.commit();
session.close();
}
@Override
public void delete(User user) {
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction
();
session.delete(user);
transaction.commit();
session.close();
}
}
import java.util.List;
public UserService() {
userDao = new UserDaoImpl();
}
Hibernate 67
user.setUsername(username);
user.setPassword(password);
userDao.save(user);
}
Hibernate 68
// Create users
userService.createUser("john_doe", "password123");
userService.createUser("jane_doe", "password456");
// Update a user
User user = userService.getUserById(1L);
if (user != null) {
userService.updateUser(user.getId(), "john_doe_
updated", "newpassword123");
}
// Delete a user
userService.deleteUser(1L);
10.5 Conclusion
Hibernate 69
The DAO pattern provides a clear and maintainable structure for managing data
access in Hibernate applications. By separating the data access logic from the
business logic, you can achieve a modular, reusable, and testable codebase.
The example provided demonstrates how to implement and use the DAO
pattern effectively with Hibernate, laying a solid foundation for building robust
applications.
In the next chapter, we will explore the Hibernate Query Language (HQL) and its
powerful features for querying the database in a more object-oriented way.
Hibernate 70
Query query = session.createQuery(hql);
List<User> users = query.list();
Example of QBC
Query<User> q = session.createQuery(query);
List<User> users = q.getResultList();
Hibernate 71
@Entity
@Table(name = "users")
@NamedQueries({
@NamedQuery(name = "User.findAll", query = "FROM Use
r"),
@NamedQuery(name = "User.findByUsername", query = "FROM
User u WHERE u.username = :username")
})
public class User {
// Entity fields and methods
}
This query will fetch all instances of Employee and its subclasses.
Hibernate 72
Positional parameters are denoted by ? followed by the parameter index in the
HQL query.
transaction.commit();
session.close();
Hibernate 73
System.out.println(user.getUsername());
}
Query<User> q = session.createQuery(query);
List<User> users = q.getResultList();
transaction.commit();
session.close();
transaction.commit();
session.close();
Hibernate 74
System.out.println(user.getUsername());
11.5 Conclusion
Hibernate Query Language (HQL) provides a powerful and flexible way to
interact with your database through Hibernate's ORM capabilities. It supports a
wide range of querying options, including polymorphic queries, positional and
named parameters, and integrates seamlessly with SQL, Criteria API, Native
Queries, and Named Queries. By leveraging these tools, developers can write
more readable, maintainable, and efficient data access code.
In the next chapter, we will delve into handling primary keys in Hibernate,
covering simple, custom, and composite primary keys.
Hibernate 75
Hibernate supports several strategies for auto-generating primary keys:
import javax.persistence.*;
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
In this example, the id field is the primary key, and its value is automatically
generated using the database's identity column.
import javax.persistence.*;
@Entity
Hibernate 76
@Table(name = "employees")
public class Employee {
@Id
private Long id;
In this case, you need to ensure that the id value is set manually before
persisting the entity.
Hibernate 77
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
</dependencies>
Hibernate 78
<property name="hibernate.dialect">org.hibernate.di
alect.MySQL8Dialect</property>
import javax.persistence.*;
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Hibernate 79
// Getters and setters
}
Creating an Employee
Reading an Employee
Updating an Employee
Hibernate 80
Deleting an Employee
// Create employee
createEmployee(session, "John Doe", "Engineering");
// Fetch employee
Employee employee = getEmployeeById(session, 1L);
System.out.println("Employee: " + employee.getName
());
// Update employee
updateEmployee(session, 1L, "John Doe", "Marketin
g");
Hibernate 81
// Delete employee
deleteEmployee(session, 1L);
// Verify deletion
Employee deletedEmployee = getEmployeeById(session,
1L);
if (deletedEmployee == null) {
System.out.println("Employee successfully delet
ed");
}
session.close();
sessionFactory.close();
}
}
12.5 Conclusion
Defining and using a simple primary key in Hibernate is straightforward and
essential for ensuring the uniqueness and integrity of database records. By
leveraging the @Id and @GeneratedValue annotations, developers can easily
manage primary keys, enabling efficient CRUD operations and data
management. The provided examples demonstrate how to implement and test
these concepts effectively.
In the next chapter, we will explore custom primary keys and how to handle
more complex primary key requirements in Hibernate.
Hibernate 82
custom primary keys can be implemented using various strategies, including
custom sequences, UUIDs, and composite keys.
import javax.persistence.*;
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, gen
erator = "custom_seq")
@SequenceGenerator(name = "custom_seq", sequenceName =
"custom_sequence", allocationSize = 1)
private Long id;
Hibernate 83
UUIDs (Universally Unique Identifiers) are 128-bit values that can be used to
uniquely identify records across distributed systems. They are particularly
useful when dealing with distributed databases or ensuring global uniqueness.
Example of UUID
First, add a dependency for UUID generation if not already included:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.32.Final</version>
</dependency>
import javax.persistence.*;
import java.util.UUID;
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(columnDefinition = "BINARY(16)")
private UUID id;
Hibernate 84
First, create the custom identifier generator:
import org.hibernate.engine.spi.SharedSessionContractImplem
entor;
import org.hibernate.id.IdentifierGenerator;
import java.io.Serializable;
import java.util.UUID;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "com.exampl
e.CustomUUIDGenerator")
private String id;
Hibernate 85
13.3 Practical Example
Let's walk through a complete example of defining and using a custom primary
key in Hibernate using a UUID strategy.
Hibernate 86
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="hibernate.connection.driver_class">
com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysq
l://localhost:3306/your_database</property>
<property name="hibernate.connection.username">your
_username</property>
<property name="hibernate.connection.password">your
_password</property>
Hibernate 87
<property name="hibernate.hbm2ddl.auto">update</pro
perty>
import javax.persistence.*;
import java.util.UUID;
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(columnDefinition = "BINARY(16)")
private UUID id;
Creating an Employee
Hibernate 88
employee.setDepartment(department);
session.save(employee);
transaction.commit();
}
Reading an Employee
Updating an Employee
Deleting an Employee
Hibernate 89
13.3.5 Testing the CRUD Operations
Create a simple test class to verify the CRUD operations.
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import java.util.UUID;
// Create employee
createEmployee(session, "John Doe", "Engineering");
// Fetch employee
Employee employee = getEmployeeById(session, UUID.f
romString("your-uuid-string"));
System.out.println("Employee: " + employee.getName
());
// Update employee
updateEmployee(session, UUID.fromString("your-uuid-
string"), "John Doe", "Marketing");
// Delete employee
deleteEmployee(session, UUID.fromString("your-uuid-
string"));
Hibernate 90
// Verify deletion
Employee deletedEmployee = getEmployeeById(session,
UUID.fromString("your-uuid-string"));
if (deletedEmployee == null) {
System.out.println("Employee successfully delet
ed");
}
session.close();
sessionFactory.close();
}
) {
Hibernate 91
employee.setName(name);
employee.setDepartment(department);
session.update(employee);
}
transaction.commit();
}
13.4 Conclusion
Custom primary keys in Hibernate provide flexibility and control over how
entities are uniquely identified. By using strategies such as custom sequences,
UUIDs, and custom identifier generators, developers can tailor primary key
generation to meet specific requirements. The provided examples demonstrate
how to implement and test these custom primary key strategies effectively.
In the next chapter, we will explore composite primary keys, which are essential
for complex key structures involving multiple columns.
Hibernate 92
is often used in cases where a single column cannot uniquely identify a record,
especially in many-to-many relationships and complex business logic
scenarios.
In Hibernate, composite primary keys can be implemented using either the
@IdClass annotation or the @EmbeddedId annotation. Each approach has its use
cases and benefits.
import java.io.Serializable;
import java.util.Objects;
// Default constructor
public EmployeeId() {}
// Parameterized constructor
public EmployeeId(Long employeeId, Long departmentId) {
this.employeeId = employeeId;
this.departmentId = departmentId;
}
Hibernate 93
this.employeeId = employeeId;
}
@Override
public int hashCode() {
return Objects.hash(employeeId, departmentId);
}
}
import javax.persistence.*;
@Entity
@IdClass(EmployeeId.class)
@Table(name = "employee_department")
public class EmployeeDepartment {
Hibernate 94
@Id
private Long employeeId;
@Id
private Long departmentId;
Hibernate 95
entity class.
import javax.persistence.Embeddable;
import java.io.Serializable;
import java.util.Objects;
@Embeddable
public class EmployeeDepartmentId implements Serializable {
private Long employeeId;
private Long departmentId;
// Default constructor
public EmployeeDepartmentId() {}
// Parameterized constructor
public EmployeeDepartmentId(Long employeeId, Long depar
tmentId) {
this.employeeId = employeeId;
this.departmentId = departmentId;
}
Hibernate 96
this.departmentId = departmentId;
}
@Override
public int hashCode() {
return Objects.hash(employeeId, departmentId);
}
}
import javax.persistence.*;
@Entity
@Table(name = "employee_department")
public class EmployeeDepartment {
@EmbeddedId
private EmployeeDepartmentId id;
Hibernate 97
}
Hibernate 98
-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
</dependencies>
Hibernate 99
<!-- Specify dialect -->
<property name="hibernate.dialect">org.hibernate.di
alect.MySQL8Dialect</property>
import javax.persistence.*;
@Entity
@Table(name = "employee_department")
public class EmployeeDepartment {
@EmbeddedId
private EmployeeDepartmentId id;
Hibernate 100
// Getters and setters
public EmployeeDepartmentId getId() {
return id;
}
Creating an EmployeeDepartment
Reading an EmployeeDepartment
Hibernate 101
public EmployeeDepartment getEmployeeDepartmentById(Session
session, Long employeeId, Long departmentId) {
EmployeeDepartmentId id =
Updating an EmployeeDepartment
Deleting an EmployeeDepartment
Hibernate 102
transaction.commit();
}
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
Hibernate 103
deleteEmployeeDepartment(session, 1L, 1L);
// Verify deletion
EmployeeDepartment deletedEmployeeDepartment = getE
mployeeDepartmentById(session, 1L, 1L);
if (deletedEmployeeDepartment == null) {
System.out.println("Employee department success
fully deleted");
}
session.close();
sessionFactory.close();
}
Hibernate 104
();
EmployeeDepartmentId id = new EmployeeDepartmentId
(employeeId, departmentId);
EmployeeDepartment employeeDepartment = session.get
(EmployeeDepartment.class, id);
if (employeeDepartment != null) {
employeeDepartment.setRole(role);
session.update(employeeDepartment);
}
transaction.commit();
}
14.5 Conclusion
Composite primary keys in Hibernate provide a robust way to handle complex
key structures involving multiple columns. By using annotations like @IdClass
and @EmbeddedId , developers can easily define and manage composite keys,
ensuring the uniqueness and integrity of their data. The provided examples
demonstrate how to implement and test composite primary keys effectively.
Hibernate 105
Chapter 15: Introduction to Transaction
Management
15.1 Introduction to Transaction Management
Transaction management is a fundamental concept in any database-related
application. In Hibernate, transaction management ensures that a group of
operations are executed in a secure and reliable manner, maintaining data
consistency and integrity. Transactions in Hibernate can be managed
programmatically or declaratively using various frameworks like JTA or Spring.
15.2.1 Atomicity
Atomicity ensures that a series of operations within a transaction are treated as
a single unit. Either all operations succeed, or none of them do. This property
prevents partial updates to the database, which could lead to data
inconsistency.
15.2.2 Consistency
Consistency ensures that a transaction transforms the database from one valid
state to another valid state. After a transaction completes, all data integrity
constraints must be satisfied. This means that any given transaction will bring
the database from one valid state to another, maintaining database rules.
15.2.3 Isolation
Isolation ensures that the operations within a transaction are isolated from the
operations in other transactions. This prevents data anomalies due to
concurrent transactions. The isolation level determines the degree to which the
operations in one transaction are isolated from those in other transactions.
15.2.4 Durability
Durability ensures that once a transaction has been committed, it remains
committed even in the case of a system failure. This means that the data
Hibernate 106
changes made by the transaction are permanently saved in the database.
Solution
Use a higher isolation level like READ_COMMITTED or above to prevent dirty reads.
Hibernate default is READ_COMMITTED .
Solution
Use the REPEATABLE_READ isolation level to ensure that once a row is read, it
cannot be modified by other transactions until the first transaction completes.
Solution
Use the SERIALIZABLE isolation level to prevent phantom reads, which ensures
complete isolation from other transactions.
Hibernate 107
15.4 Types of Transactions
In Hibernate, transactions can be managed in several ways, including
programmatically using Hibernate API, JTA (Java Transaction API), and CMT
(Container Managed Transactions).
Example
Example
import javax.transaction.UserTransaction;
import javax.naming.InitialContext;
import javax.naming.NamingException;
Hibernate 108
try {
userTransaction.begin();
// Perform database operations
userTransaction.commit();
} catch (Exception e) {
userTransaction.rollback();
e.printStackTrace();
}
@Stateless
public class EmployeeService {
@PersistenceContext
private EntityManager entityManager;
@Service
@Transactional
public class EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
Hibernate 109
public void createEmployee(Employee employee) {
employeeRepository.save(employee);
}
15.5 Conclusion
Transaction management is crucial for maintaining data integrity and
consistency in any application. Understanding and correctly implementing the
ACID properties, addressing concurrency issues, and choosing the appropriate
type of transaction management are essential skills for developers working with
Hibernate. By leveraging programmatic transactions, JTA, and CMT, developers
can ensure robust transaction handling in their applications.
In the next chapter, we will explore Hibernate connection management,
including JDBC transactions, JTA transactions, and CMT transactions, and how
they integrate with the Hibernate framework.
Hibernate 110
Session interface, which encapsulates the JDBC connection and transaction
management.
Example:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
// Create a SessionFactory
SessionFactory sessionFactory = configuration.build
SessionFactory();
// Open a session
Session session = sessionFactory.openSession();
// Begin a transaction
Transaction transaction = session.beginTransaction
();
try {
// Perform some database operations
MyEntity entity = new MyEntity();
entity.setName("Example Name");
session.save(entity);
Hibernate 111
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
// Close the session
session.close();
}
Details:
import javax.transaction.UserTransaction;
import javax.naming.InitialContext;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
Hibernate 112
public static void main(String[] args) {
try {
// Obtain the JTA UserTransaction
InitialContext context = new InitialContext();
UserTransaction userTransaction = (UserTransact
ion) context.lookup("java:comp/UserTransaction");
// Create a SessionFactory
SessionFactory sessionFactory = configuration.b
uildSessionFactory();
// Open a session
Session session = sessionFactory.openSession();
Hibernate 113
n
e.printStackTrace();
try {
userTransaction.rollback();
} catch (Exception rollbackException) {
rollbackException.printStackTrace();
}
}
}
}
Details:
Example:
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class CMTTransactionExample {
@PersistenceContext
Hibernate 114
private EntityManager entityManager;
Details:
EntityManager: The JPA interface used for interacting with the persistence
context.
Summary:
Hibernate 115
interaction between the application and the database. SessionFactory is a thread-
safe, immutable object created once during application initialization and used to
create multiple Session objects.
Key Characteristics:
Example:
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
static {
try {
// Create the SessionFactory from hibernate.cf
g.xml
sessionFactory = new Configuration().configure
().buildSessionFactory();
} catch (Throwable ex) {
// Log the exception as it might be swallowed
System.err.println("Initial SessionFactory crea
tion failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
Hibernate 116
Details:
2. Persistent State:
An object is in the persistent state if it is associated with an active Hibernate
Session and is synchronized with the database. Hibernate manages the object's
lifecycle and any changes made to it will be reflected in the database when the
transaction is committed.
3. Detached State:
An object is in the detached state if it was once persistent but its
has been closed. The object is no longer managed by Hibernate, and
Session
Hibernate 117
Session session = sessionFactory.openSession();
session.beginTransaction();
MyEntity entity = new MyEntity();
entity.setName("Detached State");
session.save(entity);
session.getTransaction().commit();
session.close();
// Detached state
entity.setName("Updated Detached State");
// Transient state
MyEntity entity = new MyEntity();
entity.setName("Transient State");
// Persistent state
Session session = sessionFactory.openSession();
Hibernate 118
session.beginTransaction();
session.save(entity);
session.getTransaction().commit();
session.close();
// Detached state
entity.setName("Updated Detached State");
Summary
In this chapter, we explored the SessionFactory , the backbone of Hibernate,
responsible for creating Session instances. We also delved into the different
object states: transient, persistent, and detached, each representing different
phases in the lifecycle of an entity managed by Hibernate. Understanding these
concepts is essential for effectively using Hibernate in your applications.
In the next chapter, we will introduce Hibernate caching mechanisms, exploring
the different types and architecture of Hibernate cache.
Hibernate 119
performance.
1. First-Level Cache (Session Cache):
Example:
session.getTransaction().commit();
session.close();
2. Second-Level Cache:
Example Configuration:
To enable the second-level cache, you need to configure it in the Hibernate
configuration file (
hibernate.cfg.xml ) and specify a caching provider (e.g., Ehcache).
Hibernate 120
<!-- hibernate.cfg.xml -->
<hibernate-configuration>
<session-factory>
<!-- Other configurations -->
Example Usage:
Hibernate 121
anotherSession.getTransaction().commit();
anotherSession.close();
Behavior: Each session maintains its own cache. Objects loaded during a
session are stored in this cache and are cleared when the session is closed.
2. Second-Level Cache:
3. Query Cache:
Configuration:
<property name="hibernate.cache.use_query_cache">true</p
roperty>
Example Usage:
Hibernate 122
session.getTransaction().commit();
session.close();
Summary
In this chapter, we explored the two main types of Hibernate cache: the first-
level cache, which is session-specific and enabled by default, and the second-
level cache, which is shared across sessions and needs to be explicitly
configured. We also touched on the query cache, an optional cache for caching
query results. Understanding and configuring these caching mechanisms can
significantly enhance the performance of your Hibernate applications by
reducing the load on the database.
In the next chapter, we will discuss Hibernate Inheritance Mapping, covering
Table Per Class Mapping and Table Per Concrete Class Mapping techniques.
Hibernate 123