Java Hibernate Cheat Sheet
Details Hibernate entity mapping annotations, session CRUD operations, HQL and Criteria queries, fetch types, and entity lifecycle states.
Entity Mapping
Map a Java class to a database table with JPA/Hibernate annotations.
@Entity@Table(name = "employees")public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "full_name", nullable = false, length = 100) private String name; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "department_id") private Department department; @OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, orphanRemoval = true) private List<Address> addresses = new ArrayList<>(); // getters/setters}
Session & CRUD Operations
Basic Hibernate Session lifecycle and persistence operations.
SessionFactory sessionFactory = new Configuration() .configure("hibernate.cfg.xml") .buildSessionFactory();try (Session session = sessionFactory.openSession()) { Transaction tx = session.beginTransaction(); Employee emp = new Employee(); emp.setName("Ada Lovelace"); session.persist(emp); // INSERT Employee found = session.get(Employee.class, 1L); // SELECT by id found.setName("Ada L."); // dirty checking auto-updates on flush session.remove(found); // DELETE tx.commit();}
HQL & Criteria API
Query entities with HQL and the type-safe Criteria API.
// HQL (object-oriented, entity/field names, not table/column names)List<Employee> results = session.createQuery( "FROM Employee e WHERE e.department.name = :dept", Employee.class) .setParameter("dept", "Engineering") .list();// Criteria API (type-safe, JPA standard)CriteriaBuilder cb = session.getCriteriaBuilder();CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);Root<Employee> root = cq.from(Employee.class);cq.select(root).where(cb.equal(root.get("name"), "Ada L."));List<Employee> list = session.createQuery(cq).getResultList();
Fetch Types & Cascade Options
Control how associated entities are loaded and propagated.
- FetchType.LAZY- Load the association only when accessed; default for @OneToMany/@ManyToMany.
- FetchType.EAGER- Load the association immediately with the parent; default for @ManyToOne/@OneToOne.
- CascadeType.PERSIST- Saving the parent also saves associated child entities.
- CascadeType.REMOVE- Deleting the parent also deletes associated children.
- CascadeType.ALL- Applies PERSIST, MERGE, REMOVE, REFRESH, and DETACH to associations.
- orphanRemoval- Automatically deletes child entities removed from the parent's collection.
Entity Lifecycle States
The states an entity moves through in the persistence context.
- Transient- New object not associated with a Session and not saved in the DB.
- Persistent (Managed)- Associated with an active Session; changes are tracked and auto-flushed.
- Detached- Was persistent but the Session closed; changes are no longer tracked.
- Removed- Scheduled for deletion in the current transaction.
- Flush- Synchronizes in-memory persistence-context changes to the database, automatically before commit/queries or manually via session.flush().
- Merge (Reattachment)- session.merge(detachedEntity) copies a detached entity's state onto a managed instance, reattaching it to the persistence context.
Optimistic & Pessimistic Locking
Prevent lost updates under concurrent access with version checks or DB-level locks.
@Entitypublic class Account { @Id private Long id; @Version private int version; // Hibernate auto-increments; UPDATE ... WHERE id=? AND version=? private BigDecimal balance;}// Optimistic: throws OptimisticLockException if version changed since readtry { Account acc = session.get(Account.class, 1L); acc.setBalance(acc.getBalance().add(BigDecimal.TEN)); session.flush();} catch (OptimisticLockException e) { // retry or surface a conflict to the caller}// Pessimistic: takes a DB row lock (SELECT ... FOR UPDATE)Account acc = session.find(Account.class, 1L, LockModeType.PESSIMISTIC_WRITE);
Second-Level & Query Cache
Cache entities and query results across sessions to cut repeated round-trips.
// hibernate.cfg.xml / properties// hibernate.cache.use_second_level_cache=true// hibernate.cache.region.factory_class=org.hibernate.cache.jcache.internal.JCacheRegionFactory// hibernate.cache.use_query_cache=true@Entity@Cacheable@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)public class Product { @Id private Long id; private String sku;}// Explicitly cache a query's result set (needs use_query_cache=true)List<Product> results = session.createQuery( "FROM Product p WHERE p.sku = :sku", Product.class) .setParameter("sku", "ABC-1") .setCacheable(true) .list();
Entity Inheritance Strategies
Ways to map a Java class hierarchy onto relational tables.
- SINGLE_TABLE- One table for the whole hierarchy with a discriminator column; fastest queries, but nullable columns for subclass-only fields (default strategy).
- JOINED- Base table plus one table per subclass joined by primary key; normalized, no nullable waste, but requires joins to read subclass data.
- TABLE_PER_CLASS- One complete table per concrete class, no shared table; queries across the hierarchy need UNION and there's no shared identity generator.
- @MappedSuperclass- Not an entity itself; shares mapped fields (e.g. id, createdAt) with subclasses without appearing in the hierarchy or its own table.
- @DiscriminatorColumn / @DiscriminatorValue- Configures the type-tagging column name and per-subclass value used by SINGLE_TABLE and JOINED strategies.
Batch Inserts & StatelessSession
Avoid persistence-context bloat and reduce round-trips for bulk operations.
// hibernate.properties// hibernate.jdbc.batch_size=50// hibernate.order_inserts=true// hibernate.order_updates=true// Regular Session: must periodically flush + clear to avoid unbounded memory growthfor (int i = 0; i < 100_000; i++) { session.persist(new LogEntry(i)); if (i % 50 == 0) { session.flush(); session.clear(); // detach everything, keep persistence context small }}// StatelessSession: no persistence context, no dirty checking, no cascading -// much lower overhead for pure bulk load/export jobstry (StatelessSession stateless = sessionFactory.openStatelessSession()) { Transaction tx = stateless.beginTransaction(); for (int i = 0; i < 100_000; i++) { stateless.insert(new LogEntry(i)); } tx.commit();}
Entity Listeners & Auditing (Envers)
Hook lifecycle callbacks and track historical revisions of entity data.
@Entity@EntityListeners(AuditingListener.class)@org.hibernate.envers.Auditedpublic class Invoice { @Id @GeneratedValue private Long id; private Instant createdAt; private Instant updatedAt; @PrePersist void onCreate() { createdAt = updatedAt = Instant.now(); } @PreUpdate void onUpdate() { updatedAt = Instant.now(); }}// Query revision history once Envers is on the classpath and @Audited is appliedAuditReader reader = AuditReaderFactory.get(session);List<Number> revisions = reader.getRevisions(Invoice.class, 1L);Invoice atRev3 = reader.find(Invoice.class, 1L, revisions.get(2));
Watch out for the N+1 select problem with lazy associations accessed in a loop - fix it with a JOIN FETCH in HQL/JPQL or @EntityGraph rather than switching everything to EAGER.