Summary
Hibernate is a powerful Object-Relational Mapping (ORM) framework for Java that simplifies database interactions by mapping Java objects to database tables. This cheatsheet covers core Hibernate concepts including configuration, entity mapping, relationships, caching strategies, query methods (HQL, Criteria API, Native SQL), transaction management, performance optimization, and best practices. Key features include automatic dirty checking, lazy loading, multi-level caching, database independence through dialects, and seamless integration with Spring Framework.
1. Core Concepts
What is Hibernate?
- ORM (Object-Relational Mapping) framework for Java
- Maps Java objects to database tables
- Eliminates boilerplate JDBC code
- Database-independent through dialect system
Key Components
- SessionFactory: Thread-safe, heavyweight object (one per application)
- Session: Single-threaded, lightweight (one per transaction)
- Transaction: Unit of work
- Query: HQL/Criteria/Native SQL execution
2. Configuration
XML Configuration (hibernate.cfg.xml)
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/db</property>
<property name="connection.username">root</property>
<property name="connection.password">pass</property>
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<mapping class="com.example.Employee"/>
</session-factory>
</hibernate-configuration>
Java Configuration
Configuration cfg = new Configuration()
.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/db")
.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect")
.addAnnotatedClass(Employee.class);
SessionFactory factory = cfg.buildSessionFactory();
3. Entity Mapping
Basic Entity
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "emp_name", nullable = false, length = 50)
private String name;
@Temporal(TemporalType.DATE)
private Date joinDate;
@Transient
private String tempData; // Not persisted
}
ID Generation Strategies
- AUTO: Let Hibernate pick
- IDENTITY: Auto-increment column
- SEQUENCE: Database sequence
- TABLE: Separate table for IDs
- UUID: Universally unique identifier
4. Relationships
One-to-One
@Entity
public class Employee {
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id")
private Address address;
}
One-to-Many / Many-to-One
@Entity
public class Department {
@OneToMany(mappedBy = "department", cascade = CascadeType.ALL)
private List<Employee> employees;
}
@Entity
public class Employee {
@ManyToOne
@JoinColumn(name = "dept_id")
private Department department;
}
Many-to-Many
@Entity
public class Student {
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses;
}
5. Fetch Types & Cascade
Fetch Types
- EAGER: Load immediately (default for @OneToOne, @ManyToOne)
- LAZY: Load on demand (default for @OneToMany, @ManyToMany)
@OneToMany(fetch = FetchType.LAZY)
private List<Order> orders;
Cascade Types
- ALL: All operations
- PERSIST: Save operations
- MERGE: Update operations
- REMOVE: Delete operations
- REFRESH: Reload operations
- DETACH: Detach operations
6. Session Operations
CRUD Operations
// Create
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
session.save(employee);
tx.commit();
// Read
Employee emp = session.get(Employee.class, 1L); // Returns null if not found
Employee emp2 = session.load(Employee.class, 1L); // Throws exception if not found
// Update
emp.setName("New Name");
session.update(emp);
// Delete
session.delete(emp);
// Merge (for detached objects)
session.merge(emp);
7. Object States
- Transient: New object, not associated with session
- Persistent: Associated with session, tracked for changes
- Detached: Was persistent, session closed
- Removed: Marked for deletion
Employee emp = new Employee(); // Transient
session.save(emp); // Persistent
session.close(); // Detached
session2.merge(emp); // Persistent again
8. Query Methods
HQL (Hibernate Query Language)
// Basic query
Query<Employee> query = session.createQuery("FROM Employee", Employee.class);
List<Employee> employees = query.list();
// With parameters
Query<Employee> query = session.createQuery(
"FROM Employee WHERE salary > :sal", Employee.class);
query.setParameter("sal", 50000);
// Named parameters
Query<Employee> query = session.createQuery(
"FROM Employee e WHERE e.name = :name AND e.dept = :dept");
query.setParameter("name", "John");
query.setParameter("dept", "IT");
Criteria API
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Employee> cr = cb.createQuery(Employee.class);
Root<Employee> root = cr.from(Employee.class);
// Simple query
cr.select(root);
// With conditions
cr.select(root).where(cb.gt(root.get("salary"), 50000));
// Multiple conditions
Predicate salaryPredicate = cb.gt(root.get("salary"), 50000);
Predicate deptPredicate = cb.equal(root.get("department"), "IT");
cr.where(cb.and(salaryPredicate, deptPredicate));
List<Employee> results = session.createQuery(cr).getResultList();
Native SQL
NativeQuery<Employee> query = session.createNativeQuery(
"SELECT * FROM employees WHERE salary > :sal", Employee.class);
query.setParameter("sal", 50000);
List<Employee> employees = query.list();
9. Named Queries
Define Named Query
@Entity
@NamedQuery(
name = "Employee.findByDepartment",
query = "FROM Employee e WHERE e.department = :dept"
)
@NamedNativeQuery(
name = "Employee.findHighSalary",
query = "SELECT * FROM employees WHERE salary > 100000",
resultClass = Employee.class
)
public class Employee { }
Use Named Query
Query<Employee> query = session.createNamedQuery(
"Employee.findByDepartment", Employee.class);
query.setParameter("dept", "IT");
10. Caching
First Level Cache (Session Cache)
- Enabled by default
- Session-scoped
- Automatic
Employee emp1 = session.get(Employee.class, 1L); // Database hit
Employee emp2 = session.get(Employee.class, 1L); // No database hit
Second Level Cache
- SessionFactory-scoped
- Requires configuration
- Use @Cacheable and @Cache annotations
@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee { }
Query Cache
<property name="cache.use_query_cache">true</property>
Query query = session.createQuery("FROM Employee");
query.setCacheable(true);
11. Transactions
Transaction Management
Transaction tx = null;
try {
tx = session.beginTransaction();
// Operations
tx.commit();
} catch (Exception e) {
if (tx != null) tx.rollback();
throw e;
} finally {
session.close();
}
Isolation Levels
- READ_UNCOMMITTED
- READ_COMMITTED
- REPEATABLE_READ
- SERIALIZABLE
12. Performance Optimization
N+1 Problem Solution
// Problem: N+1 queries
List<Department> depts = session.createQuery("FROM Department").list();
for (Department dept : depts) {
dept.getEmployees().size(); // Additional query for each department
}
// Solution 1: Join Fetch
List<Department> depts = session.createQuery(
"FROM Department d JOIN FETCH d.employees").list();
// Solution 2: Batch Fetching
@BatchSize(size = 10)
private List<Employee> employees;
Pagination
Query<Employee> query = session.createQuery("FROM Employee", Employee.class);
query.setFirstResult(20); // Offset
query.setMaxResults(10); // Limit
Projection
// Select specific columns
List<Object[]> results = session.createQuery(
"SELECT e.name, e.salary FROM Employee e").list();
13. Best Practices
1. Session Management
- Keep sessions short-lived
- One session per request/transaction
- Always close sessions
2. Use Lazy Loading
@OneToMany(fetch = FetchType.LAZY)
private List<Order> orders;
3. Batch Processing
for (int i = 0; i < 100000; i++) {
session.save(new Employee());
if (i % 50 == 0) { // Batch size
session.flush();
session.clear();
}
}
4. Use Appropriate Cascade
- Don't use CascadeType.ALL everywhere
- Be specific about cascade operations
5. Avoid SELECT N+1
- Use JOIN FETCH for eager loading
- Use @BatchSize for collections
14. Common Annotations
| Annotation | Purpose |
|---|---|
| @Entity | Mark class as entity |
| @Table | Specify table details |
| @Id | Primary key |
| @GeneratedValue | ID generation strategy |
| @Column | Column mapping |
| @Transient | Skip field |
| @Temporal | Date/Time type |
| @Lob | Large objects |
| @Enumerated | Enum mapping |
| @Embedded | Embedded object |
| @Version | Optimistic locking |
15. Key Concepts & Comparisons
Core Methods Comparison
| Method | Purpose | Database Hit | Use Case | Return Value |
|---|---|---|---|---|
get() |
Load entity | Immediate | When you need null check | Entity or null |
load() |
Load entity proxy | Lazy (when accessed) | When entity exists | Proxy (exception if not found) |
save() |
Insert entity | At flush/commit | New entities | Generated ID |
persist() |
Make entity persistent | At flush/commit | New entities in transaction | void |
update() |
Update detached entity | At flush/commit | Known detached entities | void |
merge() |
Copy state to persistent | At flush/commit | Detached entities (safe) | Persistent entity |
saveOrUpdate() |
Save or update | At flush/commit | Unknown entity state | Generated ID if new |
Session vs SessionFactory
| Aspect | Session | SessionFactory |
|---|---|---|
| Thread Safety | Not thread-safe | Thread-safe |
| Lifecycle | Short-lived (per transaction) | Long-lived (application scope) |
| Weight | Lightweight | Heavyweight |
| Creation Cost | Low | High |
| Instances | Many per application | One per application |
| Purpose | Unit of work interface | Factory for sessions |
Fetch Type Strategies
| Fetch Type | When Loaded | Default For | Use Case | Performance Impact |
|---|---|---|---|---|
EAGER |
Immediately with parent | @OneToOne, @ManyToOne |
Small related data | Higher memory, fewer queries |
LAZY |
On first access | @OneToMany, @ManyToMany |
Large collections | Lower memory, more queries |
Cascade Type Options
| Cascade Type | Operations Included | Use Case | Risk Level |
|---|---|---|---|
PERSIST |
Save operations | Parent-child creation | Low |
MERGE |
Update operations | Detached entity updates | Low |
REMOVE |
Delete operations | Dependent entity cleanup | High |
REFRESH |
Reload operations | Data synchronization | Low |
DETACH |
Detach operations | Session management | Low |
ALL |
All above operations | Complete lifecycle management | Very High |
ID Generation Strategy Comparison
| Strategy | How It Works | Database Support | Use Case |
|---|---|---|---|
AUTO |
Hibernate chooses best | All databases | Default choice |
IDENTITY |
Auto-increment column | MySQL, SQL Server | Single database |
SEQUENCE |
Database sequence | PostgreSQL, Oracle | High performance |
TABLE |
Separate ID table | All databases | Portability needed |
UUID |
Universal unique ID | All databases | Distributed systems |
Object State Transitions
// State transition examples
Employee emp = new Employee(); // TRANSIENT
session.save(emp); // PERSISTENT
session.close(); // DETACHED
session2.delete(emp); // REMOVED (if reattached)
| State | Description | Session Association | Database Sync |
|---|---|---|---|
| Transient | New object, not in database | No | No |
| Persistent | Managed by session | Yes | Yes (at flush) |
| Detached | Was persistent, session closed | No | No |
| Removed | Marked for deletion | Yes | Yes (at flush) |
Query Method Comparison
| Query Type | Syntax | Type Safety | Performance | Use Case |
|---|---|---|---|---|
| HQL | String-based | Runtime | Good | Simple to complex queries |
| Criteria API | Object-oriented | Compile-time | Good | Dynamic query building |
| Native SQL | Database-specific | None | Best | Database-specific features |
| Named Queries | Predefined HQL/SQL | Runtime | Best (parsed once) | Reusable queries |
Caching Levels
| Cache Level | Scope | Configuration | Use Case | Performance Impact |
|---|---|---|---|---|
| First Level | Session | Automatic | Single transaction | Eliminates repeated gets |
| Second Level | SessionFactory | Manual setup | Cross-session | Reduces database load |
| Query Cache | SessionFactory | Requires configuration | Repeated queries | Caches query results |
Dialect Examples
| Database | Dialect Class | Features |
|---|---|---|
| MySQL | MySQL5Dialect, MySQL8Dialect |
Auto-increment, specific functions |
| PostgreSQL | PostgreSQLDialect |
Sequences, advanced types |
| Oracle | OracleDialect |
Sequences, hierarchical queries |
| SQL Server | SQLServerDialect |
Identity columns, T-SQL |
| H2 | H2Dialect |
In-memory, testing |
Performance Optimization Strategies
| Problem | Solution | Implementation | Impact |
|---|---|---|---|
| N+1 Queries | JOIN FETCH | JOIN FETCH in HQL |
Reduces query count |
| Large Collections | Batch Fetching | @BatchSize(size=10) |
Optimizes lazy loading |
| Memory Usage | Lazy Loading | fetch=FetchType.LAZY |
Reduces memory footprint |
| Bulk Operations | Batch Processing | flush() and clear() every N records |
Prevents memory issues |
| Read Performance | Second Level Cache | @Cacheable + cache config |
Reduces database hits |
Common Exceptions & Solutions
| Exception | Cause | Solution |
|---|---|---|
LazyInitializationException |
Accessing lazy property after session close | Use JOIN FETCH or Open Session in View |
NonUniqueObjectException |
Duplicate object in session | Use merge() instead of update() |
StaleObjectStateException |
Optimistic locking conflict | Handle version conflicts in application |
ConstraintViolationException |
Database constraint violation | Validate data before persisting |
Architecture Layers
┌─────────────────────────────────────┐
│ Application Layer │
├─────────────────────────────────────┤
│ Hibernate API │
│ (Session, SessionFactory, Query) │
├─────────────────────────────────────┤
│ Hibernate Core │
│ (ORM Engine, Caching, Lazy) │
├─────────────────────────────────────┤
│ JDBC Layer │
├─────────────────────────────────────┤
│ Database │
└─────────────────────────────────────┘
Integration Patterns
| Pattern | Purpose | Implementation | Benefits |
|---|---|---|---|
| DAO Pattern | Data access abstraction | Repository classes | Separation of concerns |
| Session-per-Request | Web application pattern | Filter/Interceptor | Consistent session lifecycle |
| Open Session in View | Lazy loading in view | Web filter | Simplifies lazy initialization |
| Spring Integration | Declarative transactions | @Transactional |
Simplified transaction management |
16. Spring Integration
Configuration
@Configuration
@EnableTransactionManagement
public class HibernateConfig {
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan("com.example.model");
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
}
Repository Pattern
@Repository
@Transactional
public class EmployeeDAO {
@Autowired
private SessionFactory sessionFactory;
public void save(Employee emp) {
sessionFactory.getCurrentSession().save(emp);
}
}
Quick Reference & Best Practices
Essential Session Methods
| Method | Purpose | Returns | Use Case |
|---|---|---|---|
save(entity) |
Insert new record | Serializable ID | New transient entities |
persist(entity) |
Make persistent | void | JPA-compliant persistence |
update(entity) |
Update detached | void | Known detached entities |
merge(entity) |
Copy to persistent | Merged entity | Safe detached updates |
saveOrUpdate(entity) |
Insert or update | Serializable ID | Unknown entity state |
delete(entity) |
Mark for deletion | void | Entity removal |
get(Class, ID) |
Load immediately | Entity or null | When null is acceptable |
load(Class, ID) |
Load lazily | Proxy | When entity must exist |
flush() |
Force synchronization | void | Manual sync to DB |
clear() |
Clear session cache | void | Memory management |
evict(entity) |
Remove from cache | void | Selective cache clearing |
refresh(entity) |
Reload from DB | void | Sync with latest DB state |
HQL Quick Reference
| Category | Keywords | Example |
|---|---|---|
| Basic | SELECT, FROM, WHERE |
FROM Employee WHERE salary > 50000 |
| Joins | JOIN, LEFT JOIN, RIGHT JOIN |
FROM Employee e JOIN e.department d |
| Aggregation | COUNT, SUM, AVG, MAX, MIN |
SELECT COUNT(e) FROM Employee e |
| Grouping | GROUP BY, HAVING |
SELECT d.name, COUNT(e) FROM Employee e JOIN e.department d GROUP BY d.name |
| Ordering | ORDER BY, ASC, DESC |
FROM Employee ORDER BY salary DESC |
| Conditions | IN, NOT IN, BETWEEN, LIKE |
WHERE e.department IN ('IT', 'HR') |
| Null Checks | IS NULL, IS NOT NULL |
WHERE e.manager IS NOT NULL |
| Logic | AND, OR, NOT |
WHERE e.active = true AND e.salary > 40000 |
Performance Best Practices
✅ Session Management
- Keep sessions short-lived (per request/transaction)
- Always close sessions in finally blocks
- Use one session per thread/request
- Avoid session sharing across threads
✅ Query Optimization
- Use lazy loading by default (
FetchType.LAZY) - Apply JOIN FETCH for known eager requirements
- Implement pagination for large result sets
- Use projections to select only needed columns
- Leverage batch fetching with
@BatchSize
✅ Caching Strategy
- Enable first-level cache (automatic)
- Configure second-level cache for read-heavy entities
- Use query cache for repeated queries
- Set appropriate cache regions and strategies
✅ Transaction Management
- Use proper transaction boundaries
- Handle exceptions with rollback
- Keep transactions short
- Use optimistic locking for concurrent access
✅ Bulk Operations
- Use batch processing for large datasets
- Call
flush()andclear()periodically - Use bulk update/delete HQL for mass operations
- Configure batch size in hibernate properties
Configuration Essentials
# Connection settings
hibernate.connection.driver_class=com.mysql.cj.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost:3306/mydb
hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
# Performance settings
hibernate.jdbc.batch_size=25
hibernate.order_inserts=true
hibernate.order_updates=true
hibernate.jdbc.batch_versioned_data=true
# Cache settings
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
# Development settings
hibernate.show_sql=false
hibernate.format_sql=true
hibernate.hbm2ddl.auto=validate
Common Pitfalls & Solutions
| Pitfall | Problem | Solution |
|---|---|---|
| N+1 Query Problem | One query + N additional queries | Use JOIN FETCH or @BatchSize |
| LazyInitializationException | Accessing lazy prop after session close | Initialize in session or use Open Session in View |
| Memory Leaks | Large sessions not cleared | Call clear() periodically in batch operations |
| Non-unique Object | Same entity in session twice | Use merge() instead of update() |
| Dirty Checking Overhead | Too many tracked entities | Use stateless session for read-only operations |
| Wrong Cascade | Unintended operations | Be specific about cascade types |
Troubleshooting Checklist
- Check SQL logs: Enable
show_sqlandformat_sql - Verify entity mappings: Ensure correct annotations and relationships
- Monitor session lifecycle: Check proper opening/closing
- Review transaction boundaries: Ensure proper transaction management
- Analyze query patterns: Look for N+1 problems and unnecessary queries
- Check cache configuration: Verify cache regions and strategies
- Validate database schema: Ensure entity mappings match database structure
- Review lazy loading: Check for LazyInitializationExceptions
Production Deployment Checklist
- Disable SQL logging: Set
show_sql=falsein production - Configure connection pooling: Use HikariCP or similar
- Set up monitoring: Track query performance and cache hit rates
- Enable statistics: Configure Hibernate statistics collection
- Optimize cache: Fine-tune cache regions and eviction policies
- Set appropriate timeouts: Configure query and connection timeouts
- Use validation mode: Set
hbm2ddl.auto=validatefor production - Configure batch sizes: Optimize batch processing parameters
Integration with Spring Boot
# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=user
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.hibernate.jdbc.batch_size=25
spring.jpa.properties.hibernate.order_inserts=true
Memory Management Tips
// For batch processing
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for (int i = 0; i < 100000; i++) {
Employee emp = new Employee("Name" + i);
session.save(emp);
if (i % 50 == 0) { // Batch size
session.flush(); // Execute SQL
session.clear(); // Clear persistence context
}
}
tx.commit();
session.close();
Testing Best Practices
// Use H2 in-memory database for tests
@TestPropertySource(properties = {
"spring.datasource.url=jdbc:h2:mem:testdb",
"spring.jpa.hibernate.ddl-auto=create-drop"
})
@DataJpaTest
class EmployeeRepositoryTest {
@Autowired
private TestEntityManager entityManager;
@Test
void testFindByDepartment() {
// Test implementation
entityManager.flush(); // Force SQL execution
entityManager.clear(); // Clear persistence context
}
}