Add Hibernate 7 batches 2-6, batch 7, and batch 8: mapping styles, JPA annotations, natural IDs, @Immutable, stored procedures, in-memory test databases, JNDI mocking, proxies, associations, temporal mapping, named queries, HQL, Criteria API, EntityManager bootstrapping, Ehcache 3 L2 cache configuration, HikariCP connection pooling, Hibernate Validator CDI integration, aggregate functions, sorting, pagination, interceptors, and Hibernate Search 8 (Hibernate 7.4.5.Final + Spring Boot 4.1.1 + JDK 25)

This commit is contained in:
2026-09-20 06:06:42 +00:00
committed by Claude
commit 8568c0ce6c
330 changed files with 23668 additions and 0 deletions
@@ -0,0 +1,154 @@
package com.ankurm.hibernatedemo.scenario;
import com.ankurm.hibernatedemo.model.Book;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
/**
* Backs ankurm.com post 4859 ("Hibernate 7: get() vs load()") and
* docs/01-get-vs-load.md. Captured verbatim into docs/output/get-vs-load.txt by
* {@code scripts/run.sh getvsload}.
*
* <p>Each step opens its own {@link EntityManager} deliberately, so the SQL log lines that
* bracket a step are unambiguously that step's own traffic &mdash; there is no shared session
* whose first-level cache could quietly answer a later {@code get()} for free.
*/
@Component
@Profile("getvsload")
public class GetVsLoadRunner implements CommandLineRunner {
private static final Logger DEMO = LoggerFactory.getLogger("DEMO");
private final EntityManagerFactory emf;
public GetVsLoadRunner(EntityManagerFactory emf) {
this.emf = emf;
}
@Override
public void run(String... args) {
Long existingId = seedOneBook();
long missingId = existingId + 999_000L;
step1_getExisting(existingId);
step2_getMissing(missingId);
step3_getReferenceExisting_noSelectUntilAccessed(existingId);
step4_getReferenceMissing_exceptionOnlyOnAccess(missingId);
step5_getReferenceThenSessionClosed_lazyInitException(existingId);
step6_proxyVsRealIdentity(existingId);
}
private Long seedOneBook() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Book book = new Book("Effective Java", "Joshua Bloch");
em.persist(book);
em.getTransaction().commit();
Long id = book.getId();
em.close();
DEMO.info("SEED: inserted Book id={}", id);
return id;
}
private void step1_getExisting(Long id) {
DEMO.info("--- Step 1: session.get() on an existing id ---");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Session session = em.unwrap(Session.class);
DEMO.info("about to call session.get(Book.class, {})", id);
Book book = session.get(Book.class, id);
DEMO.info("get() returned: {}", book);
em.getTransaction().commit();
em.close();
}
private void step2_getMissing(long missingId) {
DEMO.info("--- Step 2: session.get() on a missing id ---");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Session session = em.unwrap(Session.class);
DEMO.info("about to call session.get(Book.class, {})", missingId);
Book book = session.get(Book.class, missingId);
DEMO.info("get() returned: {} (no exception thrown)", book);
em.getTransaction().commit();
em.close();
}
private void step3_getReferenceExisting_noSelectUntilAccessed(Long id) {
DEMO.info("--- Step 3: session.getReference() on an existing id ---");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Session session = em.unwrap(Session.class);
Book proxy = session.getReference(Book.class, id);
DEMO.info("getReference() returned proxy of class {} -- no SELECT above this line", proxy.getClass().getName());
DEMO.info("now calling proxy.getTitle() ...");
String title = proxy.getTitle();
DEMO.info("getTitle() returned '{}' -- the SELECT for this ran just above this line", title);
em.getTransaction().commit();
em.close();
}
private void step4_getReferenceMissing_exceptionOnlyOnAccess(long missingId) {
DEMO.info("--- Step 4: session.getReference() on a missing id ---");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Session session = em.unwrap(Session.class);
Book proxy = session.getReference(Book.class, missingId);
DEMO.info("getReference() returned a proxy for a row that does not exist -- no exception yet: {}", proxy.getClass().getName());
try {
proxy.getTitle();
DEMO.info("no exception -- this line should be unreachable");
} catch (RuntimeException e) {
DEMO.info("accessing the proxy threw {}: {}", e.getClass().getName(), e.getMessage());
}
em.getTransaction().rollback();
em.close();
}
private void step5_getReferenceThenSessionClosed_lazyInitException(Long id) {
DEMO.info("--- Step 5: proxy accessed after its session is closed ---");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Session session = em.unwrap(Session.class);
Book proxy = session.getReference(Book.class, id);
em.getTransaction().commit();
em.close();
DEMO.info("session closed. proxy in hand: {}", proxy.getClass().getName());
try {
proxy.getTitle();
DEMO.info("no exception -- this line should be unreachable");
} catch (RuntimeException e) {
DEMO.info("accessing the proxy after close threw {}: {}", e.getClass().getName(), e.getMessage());
}
}
private void step6_proxyVsRealIdentity(Long id) {
DEMO.info("--- Step 6: proxy identity vs a real loaded instance ---");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Session session = em.unwrap(Session.class);
Book real = session.get(Book.class, id);
// second em/session so this is a genuinely separate proxy, not the same cached instance
EntityManager em2 = emf.createEntityManager();
em2.getTransaction().begin();
Session session2 = em2.unwrap(Session.class);
Book proxy = session2.getReference(Book.class, id);
DEMO.info("real.getClass() = {}", real.getClass().getName());
DEMO.info("proxy.getClass() = {}", proxy.getClass().getName());
DEMO.info("proxy instanceof Book.class: {}", Book.class.isInstance(proxy));
DEMO.info("real.getClass() == proxy.getClass(): {}", real.getClass() == proxy.getClass());
DEMO.info("real.equals(proxy) before proxy access: {}", real.equals(proxy));
em.getTransaction().commit();
em.close();
em2.getTransaction().commit();
em2.close();
}
}