In any database-driven application, CRUD (Create, Read, Update, Delete) operations are at the core. Hibernate, a powerful Object-Relational Mapping (ORM) framework in Java, makes CRUD simple and efficient by allowing developers to work directly with Java objects instead of raw SQL queries.
This tutorial will guide you step-by-step through performing basic CRUD with Hibernate, complete with entity mapping, configuration, CRUD code examples, and best practices for production-ready applications.
Setup and Configuration
Maven Dependency
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.4.1.Final</version>
</dependency>
Hibernate Configuration (hibernate.cfg.xml)
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/testdb</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.show_sql">true</property>
<mapping class="com.example.Student"/>
</session-factory>
</hibernate-configuration>
Entity Class
import jakarta.persistence.*;
@Entity
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "student_name", nullable = false)
private String name;
@Column(name = "age")
private int age;
public Student() {}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// Getters and setters
}
Hibernate Utility Class (SessionFactory)
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
CRUD Operations with Hibernate
Create (Insert)
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
Student student = new Student("Alice", 22);
session.persist(student);
tx.commit();
session.close();
✅ Hibernate generates the INSERT
statement automatically.
Read (Select)
Session session = HibernateUtil.getSessionFactory().openSession();
Student student = session.get(Student.class, 1L);
System.out.println(student.getName() + " - " + student.getAge());
session.close();
✅ Uses the primary key to fetch an entity.
Update
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
Student student = session.get(Student.class, 1L);
student.setName("Updated Alice");
student.setAge(23);
session.update(student);
tx.commit();
session.close();
✅ Hibernate generates an UPDATE
statement.
Delete
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
Student student = session.get(Student.class, 1L);
session.remove(student);
tx.commit();
session.close();
✅ Hibernate generates a DELETE
statement.
Querying Data
HQL Example
List<Student> students = session.createQuery("FROM Student WHERE age > :age", Student.class)
.setParameter("age", 20)
.list();
Criteria API Example
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Student> cq = cb.createQuery(Student.class);
Root<Student> root = cq.from(Student.class);
cq.select(root).where(cb.greaterThan(root.get("age"), 20));
List<Student> results = session.createQuery(cq).getResultList();
Native SQL Example
List<Object[]> results = session.createNativeQuery("SELECT * FROM students").list();
Caching and Performance Considerations
- First-Level Cache → Session-specific, automatic.
- Second-Level Cache → Application-wide, requires providers like EHCache.
- Lazy Loading (default) → Data fetched only when needed.
- Eager Loading → Fetches immediately.
Analogy:
- Lazy loading = ordering food only when hungry.
- Caching = remembering your previous order instead of asking the kitchen again.
Real-World Integration with Spring Boot
Spring Boot simplifies Hibernate CRUD with Spring Data JPA.
spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
Repository Example:
public interface StudentRepository extends JpaRepository<Student, Long> {}
Common Pitfalls
- Forgetting to close sessions → memory leaks.
- Using eager fetching everywhere → performance issues.
- Misconfigured cascades → unintended deletes.
- Using
IDENTITY
strategy with batch inserts → performance bottlenecks.
Best Practices
- Always wrap operations in transactions.
- Close sessions after use.
- Use lazy fetching by default.
- DTOs for APIs instead of exposing entities.
- Enable batch operations and tune caching.
📌 Hibernate Version Notes
Hibernate 5.x
- Relies on
javax.persistence
. - Classic SessionFactory and legacy APIs.
Hibernate 6.x
- Uses
jakarta.persistence
. - Enhanced query APIs.
- Improved SQL integration.
Conclusion and Key Takeaways
- CRUD is the foundation of database interaction.
- Hibernate simplifies CRUD with Sessions, Transactions, and mappings.
- Queries can be performed via HQL, Criteria API, or native SQL.
- Caching and lazy loading improve performance.
- Hibernate integrates seamlessly with Spring Boot and JPA.
FAQ: Expert Hibernate Questions
-
What’s the difference between Hibernate and JPA?
JPA is a specification; Hibernate is a powerful implementation. -
How does Hibernate caching improve performance?
By reducing redundant database queries. -
What are the drawbacks of eager fetching?
It loads unnecessary data, consuming resources. -
How do I solve the N+1 select problem?
UseJOIN FETCH
or batch fetching. -
Can I use Hibernate without Spring?
Yes, Hibernate works standalone. -
What’s the best inheritance mapping strategy?
JOINED
for normalization,SINGLE_TABLE
for speed. -
How does Hibernate handle composite keys?
With@EmbeddedId
or@IdClass
. -
How is Hibernate 6 different from Hibernate 5?
Hibernate 6 usesjakarta.persistence
and enhances query APIs. -
Is Hibernate suitable for microservices?
Yes, but keep entities lightweight and use DTOs. -
When should I not use Hibernate?
For raw SQL-heavy analytics or high-performance batch jobs.