Hibernate Basics in Java

Hibernate is an Object-Relational Mapping (ORM) framework that simplifies database operations by mapping Java objects to database tables.

1. Introduction to Hibernate

What is Hibernate?

  • ORM Framework: Maps Java objects to database tables
  • Database Abstraction: Works with multiple databases
  • JPA Implementation: Implements Java Persistence API specification
  • Automatic SQL Generation: Generates SQL queries automatically

Key Benefits

  • Reduces boilerplate JDBC code
  • Provides caching mechanisms
  • Supports relationships and inheritance
  • Offers transaction management

2. Setup and Configuration

Maven Dependencies

<!-- pom.xml -->
<dependencies>
<!-- Hibernate Core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.3.1.Final</version>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- Connection Pool -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>
</dependencies>

Hibernate Configuration File

<!-- src/main/resources/hibernate.cfg.xml -->
<?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="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_db</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">password</property>
<!-- Connection pool settings -->
<property name="hibernate.connection.provider_class">com.zaxxer.hikari.hibernate.HikariConnectionProvider</property>
<property name="hibernate.hikari.minimumIdle">5</property>
<property name="hibernate.hikari.maximumPoolSize">20</property>
<property name="hibernate.hikari.idleTimeout">30000</property>
<!-- SQL dialect -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Echo all executed SQL to stdout -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!-- Auto create/update database schema -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- Annotated entity classes -->
<mapping class="com.example.entity.Employee"/>
<mapping class="com.example.entity.Department"/>
<mapping class="com.example.entity.Address"/>
</session-factory>
</hibernate-configuration>

Java-based Configuration (Alternative)

public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create ServiceRegistry
StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
.configure("hibernate.cfg.xml")
.build();
// Create Metadata
Metadata metadata = new MetadataSources(standardRegistry)
.addAnnotatedClass(Employee.class)
.addAnnotatedClass(Department.class)
.addAnnotatedClass(Address.class)
.getMetadataBuilder()
.build();
// Create SessionFactory
return metadata.getSessionFactoryBuilder().build();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
getSessionFactory().close();
}
}

3. Entity Mapping

Basic Entity Class

package com.example.entity;
import jakarta.persistence.*;
import java.time.LocalDateTime;
import java.util.Objects;
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "employee_id")
private Long id;
@Column(name = "first_name", nullable = false, length = 50)
private String firstName;
@Column(name = "last_name", nullable = false, length = 50)
private String lastName;
@Column(name = "email", unique = true, nullable = false, length = 100)
private String email;
@Column(name = "salary")
private Double salary;
@Enumerated(EnumType.STRING)
@Column(name = "employee_type")
private EmployeeType employeeType;
@Column(name = "hire_date")
private LocalDateTime hireDate;
@Version
@Column(name = "version")
private Long version;
// Constructors
public Employee() {}
public Employee(String firstName, String lastName, String email, Double salary) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.salary = salary;
this.hireDate = LocalDateTime.now();
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Double getSalary() { return salary; }
public void setSalary(Double salary) { this.salary = salary; }
public EmployeeType getEmployeeType() { return employeeType; }
public void setEmployeeType(EmployeeType employeeType) { this.employeeType = employeeType; }
public LocalDateTime getHireDate() { return hireDate; }
public void setHireDate(LocalDateTime hireDate) { this.hireDate = hireDate; }
public Long getVersion() { return version; }
public void setVersion(Long version) { this.version = version; }
// equals and hashCode
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Employee)) return false;
Employee employee = (Employee) o;
return Objects.equals(id, employee.id) && 
Objects.equals(email, employee.email);
}
@Override
public int hashCode() {
return Objects.hash(id, email);
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", salary=" + salary +
", hireDate=" + hireDate +
'}';
}
}
enum EmployeeType {
FULL_TIME, PART_TIME, CONTRACT
}

Entity with Relationships

package com.example.entity;
import jakarta.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "departments")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "department_id")
private Long id;
@Column(name = "department_name", unique = true, nullable = false, length = 100)
private String name;
@Column(name = "description", length = 500)
private String description;
// One-to-Many relationship
@OneToMany(mappedBy = "department", 
cascade = CascadeType.ALL, 
fetch = FetchType.LAZY)
private List<Employee> employees = new ArrayList<>();
// Many-to-Many relationship
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(
name = "department_projects",
joinColumns = @JoinColumn(name = "department_id"),
inverseJoinColumns = @JoinColumn(name = "project_id")
)
private List<Project> projects = new ArrayList<>();
// Constructors
public Department() {}
public Department(String name, String description) {
this.name = name;
this.description = description;
}
// Helper methods for bidirectional relationship
public void addEmployee(Employee employee) {
employees.add(employee);
employee.setDepartment(this);
}
public void removeEmployee(Employee employee) {
employees.remove(employee);
employee.setDepartment(null);
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public List<Employee> getEmployees() { return employees; }
public void setEmployees(List<Employee> employees) { this.employees = employees; }
public List<Project> getProjects() { return projects; }
public void setProjects(List<Project> projects) { this.projects = projects; }
}

Updated Employee with Relationships

package com.example.entity;
import jakarta.persistence.*;
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String email;
private Double salary;
// Many-to-One relationship
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id")
private Department department;
// One-to-One relationship
@OneToOne(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Address address;
// Constructors, getters, setters...
public Employee() {}
public Employee(String firstName, String lastName, String email, Double salary) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.salary = salary;
}
// Getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Double getSalary() { return salary; }
public void setSalary(Double salary) { this.salary = salary; }
public Department getDepartment() { return department; }
public void setDepartment(Department department) { this.department = department; }
public Address getAddress() { return address; }
public void setAddress(Address address) { this.address = address; }
}

Address Entity (One-to-One)

package com.example.entity;
import jakarta.persistence.*;
@Entity
@Table(name = "addresses")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "street")
private String street;
@Column(name = "city")
private String city;
@Column(name = "state")
private String state;
@Column(name = "zip_code")
private String zipCode;
@Column(name = "country")
private String country;
// One-to-One bidirectional
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "employee_id")
private Employee employee;
// Constructors
public Address() {}
public Address(String street, String city, String state, String zipCode, String country) {
this.street = street;
this.city = city;
this.state = state;
this.zipCode = zipCode;
this.country = country;
}
// Getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getStreet() { return street; }
public void setStreet(String street) { this.street = street; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getState() { return state; }
public void setState(String state) { this.state = state; }
public String getZipCode() { return zipCode; }
public void setZipCode(String zipCode) { this.zipCode = zipCode; }
public String getCountry() { return country; }
public void setCountry(String country) { this.country = country; }
public Employee getEmployee() { return employee; }
public void setEmployee(Employee employee) { this.employee = employee; }
}

4. Basic CRUD Operations

Hibernate CRUD Operations

package com.example.dao;
import com.example.entity.Employee;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import java.util.List;
import java.util.Optional;
public class EmployeeDAO {
// Create
public Long saveEmployee(Employee employee) {
Transaction transaction = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
transaction = session.beginTransaction();
Long id = (Long) session.save(employee);
transaction.commit();
return id;
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
return null;
}
}
// Read - Get by ID
public Optional<Employee> getEmployeeById(Long id) {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
Employee employee = session.get(Employee.class, id);
return Optional.ofNullable(employee);
} catch (Exception e) {
e.printStackTrace();
return Optional.empty();
}
}
// Read - Get All
public List<Employee> getAllEmployees() {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
Query<Employee> query = session.createQuery("FROM Employee", Employee.class);
return query.list();
} catch (Exception e) {
e.printStackTrace();
return List.of();
}
}
// Update
public void updateEmployee(Employee employee) {
Transaction transaction = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
transaction = session.beginTransaction();
session.update(employee);
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
}
}
// Update with merge (better for detached objects)
public void mergeEmployee(Employee employee) {
Transaction transaction = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
transaction = session.beginTransaction();
session.merge(employee);
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
}
}
// Delete
public void deleteEmployee(Long id) {
Transaction transaction = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
transaction = session.beginTransaction();
Employee employee = session.get(Employee.class, id);
if (employee != null) {
session.delete(employee);
}
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
}
}
// Custom query - Get by email
public Optional<Employee> getEmployeeByEmail(String email) {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
Query<Employee> query = session.createQuery(
"FROM Employee WHERE email = :email", Employee.class);
query.setParameter("email", email);
return query.uniqueResultOptional();
} catch (Exception e) {
e.printStackTrace();
return Optional.empty();
}
}
// Custom query - Get by salary range
public List<Employee> getEmployeesBySalaryRange(Double minSalary, Double maxSalary) {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
Query<Employee> query = session.createQuery(
"FROM Employee WHERE salary BETWEEN :minSalary AND :maxSalary", Employee.class);
query.setParameter("minSalary", minSalary);
query.setParameter("maxSalary", maxSalary);
return query.list();
} catch (Exception e) {
e.printStackTrace();
return List.of();
}
}
// Native SQL query
public List<Employee> getTopPaidEmployees(int limit) {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
Query<Employee> query = session.createNativeQuery(
"SELECT * FROM employees ORDER BY salary DESC LIMIT :limit", Employee.class);
query.setParameter("limit", limit);
return query.list();
} catch (Exception e) {
e.printStackTrace();
return List.of();
}
}
}

5. HQL (Hibernate Query Language)

HQL Examples

package com.example.dao;
import com.example.entity.Employee;
import org.hibernate.Session;
import org.hibernate.query.Query;
import java.util.List;
public class EmployeeHQLDAO {
// Basic HQL queries
public List<Employee> findAllEmployees() {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
return session.createQuery("FROM Employee", Employee.class).list();
}
}
// HQL with parameters
public List<Employee> findEmployeesByName(String firstName, String lastName) {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
Query<Employee> query = session.createQuery(
"FROM Employee WHERE firstName = :firstName AND lastName = :lastName", 
Employee.class);
query.setParameter("firstName", firstName);
query.setParameter("lastName", lastName);
return query.list();
}
}
// HQL with LIKE and ordering
public List<Employee> findEmployeesByNamePattern(String namePattern) {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
Query<Employee> query = session.createQuery(
"FROM Employee WHERE firstName LIKE :pattern OR lastName LIKE :pattern " +
"ORDER BY lastName, firstName", Employee.class);
query.setParameter("pattern", "%" + namePattern + "%");
return query.list();
}
}
// HQL with aggregation
public Double getAverageSalary() {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
Query<Double> query = session.createQuery(
"SELECT AVG(salary) FROM Employee", Double.class);
return query.uniqueResult();
}
}
// HQL with JOIN
public List<Object[]> getEmployeesWithDepartment() {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
Query<Object[]> query = session.createQuery(
"SELECT e.firstName, e.lastName, d.name FROM Employee e " +
"JOIN e.department d", Object[].class);
return query.list();
}
}
// HQL with pagination
public List<Employee> getEmployeesWithPagination(int pageNumber, int pageSize) {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
Query<Employee> query = session.createQuery(
"FROM Employee ORDER BY id", Employee.class);
query.setFirstResult((pageNumber - 1) * pageSize);
query.setMaxResults(pageSize);
return query.list();
}
}
// HQL update
public int updateEmployeeSalary(Double percentageIncrease) {
Transaction transaction = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
transaction = session.beginTransaction();
Query<?> query = session.createQuery(
"UPDATE Employee SET salary = salary * (1 + :increase)");
query.setParameter("increase", percentageIncrease / 100);
int updatedCount = query.executeUpdate();
transaction.commit();
return updatedCount;
} catch (Exception e) {
if (transaction != null) transaction.rollback();
e.printStackTrace();
return 0;
}
}
// HQL delete
public int deleteEmployeesWithLowSalary(Double minSalary) {
Transaction transaction = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
transaction = session.beginTransaction();
Query<?> query = session.createQuery(
"DELETE FROM Employee WHERE salary < :minSalary");
query.setParameter("minSalary", minSalary);
int deletedCount = query.executeUpdate();
transaction.commit();
return deletedCount;
} catch (Exception e) {
if (transaction != null) transaction.rollback();
e.printStackTrace();
return 0;
}
}
}

6. Criteria API

Criteria Query Examples

package com.example.dao;
import com.example.entity.Employee;
import org.hibernate.Session;
import org.hibernate.query.Query;
import jakarta.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;
public class EmployeeCriteriaDAO {
// Basic Criteria query
public List<Employee> findAllEmployees() {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> root = cq.from(Employee.class);
cq.select(root);
Query<Employee> query = session.createQuery(cq);
return query.list();
}
}
// Criteria with filtering
public List<Employee> findEmployeesBySalaryRange(Double minSalary, Double maxSalary) {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> root = cq.from(Employee.class);
Predicate salaryPredicate = cb.between(root.get("salary"), minSalary, maxSalary);
cq.where(salaryPredicate);
Query<Employee> query = session.createQuery(cq);
return query.list();
}
}
// Criteria with multiple conditions
public List<Employee> findEmployeesComplex(String namePattern, Double minSalary, String departmentName) {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> root = cq.from(Employee.class);
List<Predicate> predicates = new ArrayList<>();
if (namePattern != null && !namePattern.trim().isEmpty()) {
Predicate namePredicate = cb.or(
cb.like(root.get("firstName"), "%" + namePattern + "%"),
cb.like(root.get("lastName"), "%" + namePattern + "%")
);
predicates.add(namePredicate);
}
if (minSalary != null) {
predicates.add(cb.greaterThanOrEqualTo(root.get("salary"), minSalary));
}
if (departmentName != null && !departmentName.trim().isEmpty()) {
Join<Employee, Department> departmentJoin = root.join("department", JoinType.INNER);
predicates.add(cb.equal(departmentJoin.get("name"), departmentName));
}
cq.where(predicates.toArray(new Predicate[0]));
cq.orderBy(cb.asc(root.get("lastName")), cb.asc(root.get("firstName")));
Query<Employee> query = session.createQuery(cq);
return query.list();
}
}
// Criteria with projections
public List<Object[]> getEmployeeStatistics() {
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Object[]> cq = cb.createQuery(Object[].class);
Root<Employee> root = cq.from(Employee.class);
cq.multiselect(
cb.count(root),
cb.avg(root.get("salary")),
cb.max(root.get("salary")),
cb.min(root.get("salary"))
);
Query<Object[]> query = session.createQuery(cq);
return query.list();
}
}
}

7. Transaction Management

Transaction Examples

package com.example.service;
import com.example.dao.EmployeeDAO;
import com.example.entity.Employee;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class EmployeeService {
private EmployeeDAO employeeDAO = new EmployeeDAO();
// Programmatic transaction management
public void transferEmployeesBetweenDepartments(List<Long> employeeIds, Long newDepartmentId) {
Transaction transaction = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
transaction = session.beginTransaction();
// Business logic with multiple operations
for (Long employeeId : employeeIds) {
Employee employee = session.get(Employee.class, employeeId);
if (employee != null) {
// Update department logic here
// employee.setDepartment(newDepartment);
session.update(employee);
}
}
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
throw new RuntimeException("Transfer failed", e);
}
}
// Batch processing
public void batchInsertEmployees(List<Employee> employees) {
Transaction transaction = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
transaction = session.beginTransaction();
int batchSize = 30;
for (int i = 0; i < employees.size(); i++) {
session.persist(employees.get(i));
if (i % batchSize == 0 && i > 0) {
// Flush and clear session to manage memory
session.flush();
session.clear();
}
}
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
throw new RuntimeException("Batch insert failed", e);
}
}
}

8. Main Application Example

Complete Working Example

package com.example;
import com.example.dao.EmployeeDAO;
import com.example.dao.DepartmentDAO;
import com.example.entity.Employee;
import com.example.entity.Department;
import com.example.entity.Address;
import com.example.util.HibernateUtil;
public class HibernateDemo {
private static EmployeeDAO employeeDAO = new EmployeeDAO();
private static DepartmentDAO departmentDAO = new DepartmentDAO();
public static void main(String[] args) {
try {
// Demonstrate CRUD operations
demonstrateCRUDOperations();
// Demonstrate relationships
demonstrateRelationships();
// Demonstrate queries
demonstrateQueries();
} finally {
HibernateUtil.shutdown();
}
}
private static void demonstrateCRUDOperations() {
System.out.println("=== CRUD Operations Demo ===");
// Create
Employee employee = new Employee("John", "Doe", "[email protected]", 50000.0);
Long employeeId = employeeDAO.saveEmployee(employee);
System.out.println("Created employee with ID: " + employeeId);
// Read
Employee foundEmployee = employeeDAO.getEmployeeById(employeeId).orElse(null);
System.out.println("Found employee: " + foundEmployee);
// Update
foundEmployee.setSalary(55000.0);
employeeDAO.updateEmployee(foundEmployee);
System.out.println("Updated employee salary");
// Delete
employeeDAO.deleteEmployee(employeeId);
System.out.println("Deleted employee");
}
private static void demonstrateRelationships() {
System.out.println("\n=== Relationships Demo ===");
// Create department
Department itDepartment = new Department("IT", "Information Technology Department");
departmentDAO.saveDepartment(itDepartment);
// Create employees with department
Employee emp1 = new Employee("Alice", "Smith", "[email protected]", 60000.0);
Employee emp2 = new Employee("Bob", "Johnson", "[email protected]", 65000.0);
// Set relationships
itDepartment.addEmployee(emp1);
itDepartment.addEmployee(emp2);
// Create address
Address address = new Address("123 Main St", "New York", "NY", "10001", "USA");
emp1.setAddress(address);
address.setEmployee(emp1);
// Save everything
employeeDAO.saveEmployee(emp1);
employeeDAO.saveEmployee(emp2);
System.out.println("Created department with employees and address");
}
private static void demonstrateQueries() {
System.out.println("\n=== Queries Demo ===");
// Get all employees
var allEmployees = employeeDAO.getAllEmployees();
System.out.println("All employees: " + allEmployees.size());
// Get by email
var employeeByEmail = employeeDAO.getEmployeeByEmail("[email protected]");
employeeByEmail.ifPresent(emp -> 
System.out.println("Found by email: " + emp.getFirstName()));
// Get by salary range
var employeesBySalary = employeeDAO.getEmployeesBySalaryRange(50000.0, 70000.0);
System.out.println("Employees in salary range: " + employeesBySalary.size());
}
}

9. Best Practices

Configuration Best Practices

public class HibernateBestPractices {
/*
1. Use connection pooling (HikariCP recommended)
2. Configure proper dialect for your database
3. Set appropriate fetch sizes and batch sizes
4. Use second-level caching for read-heavy applications
5. Enable SQL logging only in development
6. Use proper transaction boundaries
7. Avoid N+1 query problem with proper fetching strategies
8. Use DTO projections for read-only operations
9. Implement proper equals() and hashCode() methods
10. Use optimistic locking with @Version
*/
// Example of proper equals and hashCode
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Employee)) return false;
Employee employee = (Employee) o;
return Objects.equals(getId(), employee.getId()) &&
Objects.equals(getEmail(), employee.getEmail());
}
@Override
public int hashCode() {
return Objects.hash(getId(), getEmail());
}
}

Summary

Key Hibernate Concepts:

  • Entity: Java class mapped to database table
  • Session: Main interface for database operations
  • Transaction: Atomic unit of work
  • HQL: Object-oriented query language
  • Criteria API: Type-safe query API
  • Relationships: One-to-One, One-to-Many, Many-to-One, Many-to-Many

Common Annotations:

  • @Entity, @Table, @Id, @GeneratedValue
  • @Column, @OneToMany, @ManyToOne, @OneToOne, @ManyToMany
  • @JoinColumn, @JoinTable, @Enumerated, @Version

Next Steps:

  • Learn about caching (First-level, Second-level, Query cache)
  • Explore advanced mapping (inheritance, components)
  • Study performance optimization
  • Learn about Hibernate Validator
  • Explore Spring Data JPA integration

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper