It is a standard (specification) for managing relational data in Java applications.
JPA defines how Java objects are mapped to database tables (Object-Relational Mapping or ORM)
The ORM frameworks that implement JPA include:
Hibernate
EclipseLink
OpenJPA
@Entity
public class Account {
@Id
private Long id;
private String name;
private double balance;
}
Application
|
|--> Configuration --> SessionFactory --> Session --> Transaction
|
|--> Query / Criteria
|
--> Database
Database connection settings: hibernate.cfg.xml (alternative: hibernate.properties) or annotations-based config in code.
<?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/hibernatedb</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">password</property>
<!-- JDBC dialect -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Show SQL in console -->
<property name="hibernate.show_sql">true</property>
<!-- Automatically create/update tables -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- Mapping class -->
<mapping resource="com/example/Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
.hbm.xml mapping files, or using JPA annotations (@Entity, @Table, @Id, etc.).
Building SessionFactory using hibernate.cfg.xml
It’s a thread-safe, heavyweight object — typically created once per application — one for each database.
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
.configure("hibernate.cfg.xml") // Load configuration
.build();
Metadata meta = new MetadataSources(ssr)
.getMetadataBuilder()
.build();
SessionFactory factory = meta.getSessionFactoryBuilder().build();
It represents a single connection between the app and the database — for CRUD (Create, Read, Update, Delete).
It is lightweight & not thread-safe.
Session session = factory.openSession();
// Perform any DB operations...
session.close();
Transactions group multiple operations into a single atomic unit of work.
If one operation fails → entire transaction rolls back.
Session session = factory.openSession();
Transaction t = session.beginTransaction();
try {
Employee e = new Employee(2, "Alice", 70000);
session.save(e);
t.commit(); // commit transaction
} catch (Exception ex) {
t.rollback(); // rollback on error
}
session.close();
Hibernate supports HQL (Hibernate Query Language)** and SQL queries.
HQL Example:
String hql = "FROM Employee WHERE salary > 50000";
Query query = session.createQuery(hql);
List<Employee> employees = query.list();
for (Employee e : employees) {
System.out.println(e.getName() + " - " + e.getSalary());
}
SQL Example:
String sql = "SELECT * FROM employee";
Query query = session.createSQLQuery(sql).addEntity(Employee.class);
List<Employee> list = query.list();
Instead of using employee.hbm.xml mapping file, using annotations to map.
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.persistence.Id;
import jakarta.persistence.Column;
@Entity // Marks this class as a persistent entity
@Table(name = "employee") // Maps to "employee" table
public class Employee {
@Id
@Column(name = "id") // Maps to "id" column
private int id;
@Column(name = "name") // Maps to "name" column
private String name;
@Column(name = "salary") // Maps to "salary" column
private double salary;
// Constructors
public Employee() {}
public Employee(int id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
// Getters and setters
}
Replacement for the old Hibernate Criteria interface.
JPA Criteria API allows to build dynamic queries in a type-safe, object-oriented way — instead of writing query strings (like HQL or JPQL). It's based on JPA (Java Persistence API).
CriteriaBuilder: Factory used to construct criteria queries, expressions, predicates, etc.
CriteriaQuery<T>: Represents a query returning objects of type T.
Root<T>: Defines a query source (typically a mapped entity class).
Predicate: Represents WHERE clause conditions.
TypedQuery<T>: Executes the query and returns the results.
Create CriteriaBuilder from the session
CriteriaBuilder cb = session.getCriteriaBuilder();
Create CriteriaQuery: What type of object the query should return (here, Employee).
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Define Query Root (FROM Clause): Which entity class to query.
Root<Employee> root = cq.from(Employee.class);
Build WHERE Clause (Optional)
Example: Get employees with salary greater than 50000.
cq.select(root).where(cb.gt(root.get("salary"), 50000));
Here:
cb.gt → “greater than” condition.
root.get("salary") → refers to the salary field of Employee.
Create and Execute Query
Query<Employee> query = session.createQuery(cq);
List<Employee> results = query.getResultList();
for (Employee e : results) {
System.out.println(e.getName() + " - " + e.getSalary());
}
Equality: cb.equal(root.get("name"), "John")
Inequality: cb.notEqual(root.get("id"), 10)
Greater than / Greater or equal: cb.gt(root.get("salary"), 50000); cb.ge(root.get("salary"), 50000)
Less than / Less or equal: cb.le(root.get("salary"), 30000)
Pattern matching: cb.like(root.get("name"), "A%")
Combine conditions: cb.and(pred1, pred2)
Logical OR: cb.or(pred1, pred2)
Range check: cb.between(root.get("salary"), 30000, 60000)
Sorting: cq.orderBy(cb.desc(root.get("salary")))