337 lines
30 KiB
Markdown
Executable File
337 lines
30 KiB
Markdown
Executable File
# hibernate-demo
|
||
|
||
Companion repository for a batch of twenty-six ankurm.com chapters on Hibernate 7: the
|
||
persistence-context APIs (`get()` vs `getReference()`, `merge()` vs `refresh()`, batch inserts),
|
||
mapping styles (annotations vs. XML, JPA persistence annotations, natural ids, immutable
|
||
entities), a set of deeper operational topics (stored procedures, in-memory test databases,
|
||
mocking JNDI datasources, proxies and lazy initialization, association mappings, date/time
|
||
mapping, and named queries), the query layer (HQL, the Criteria API with a real generated
|
||
metamodel, and bootstrapping `EntityManagerFactory` outside Spring entirely), second-level
|
||
cache configuration with Ehcache 3 (entity caching, query caching, bulk-mutation cache
|
||
invalidation, and JCache provider setup), HikariCP connection pooling (Spring Boot's default
|
||
pool, raw non-Spring bootstrap, pool exhaustion, and leak detection), Jakarta Bean
|
||
Validation's CDI integration (constraint validator dependency injection, with and without a
|
||
running CDI container), aggregate functions (empty-result-set behavior, `select new` records,
|
||
and HQL window functions), sorting (`@OrderBy`, `@SortNatural`/`@SortComparator`, dynamic-sort
|
||
injection, and null precedence via `jakarta.persistence.criteria.Nulls`), pagination
|
||
(`setFirstResult`/`setMaxResults`, `ScrollableResults`, when a `join fetch` actually falls back
|
||
to in-memory pagination, and keyset pagination), interceptors (implementing `Interceptor`
|
||
directly now that every method is a default method, session-scoped vs. globally-registered
|
||
interceptors, and bulk updates bypassing them), and Hibernate Search 8 (full-text and keyword
|
||
fields, fuzzy matching, `@IndexedEmbedded`, and `MassIndexer`). Every claim in
|
||
those chapters that comes from this repo traces to a named JUnit test here and a captured
|
||
transcript in `docs/output/` — nothing is asserted that wasn't actually run.
|
||
|
||
## Versions
|
||
|
||
| Component | Version | Notes |
|
||
|---|---|---|
|
||
| Spring Boot | `4.1.1` | parent POM |
|
||
| Hibernate ORM | `7.4.5.Final` | what Boot 4.1.1 manages — see [`docs/00-versions.md`](docs/00-versions.md) for why this is *not* the same patch Boot 4.1.0 resolves |
|
||
| Spring Framework | `7.0.9` | pulled in transitively by Boot 4.1.1 |
|
||
| Jakarta Persistence | `3.2.0` | `jakarta.persistence-api` |
|
||
| Java | `25` (Temurin 25.0.4.1 LTS) | |
|
||
| H2 | `2.4.240` | in-memory, `DB_CLOSE_DELAY=-1` |
|
||
| HSQLDB | `2.7.3` | in-memory |
|
||
| Apache Derby | `10.16.1.1` | in-memory; needs `hibernate-community-dialects` (see below) |
|
||
| simple-jndi | `0.25.0` | `com.github.h-thurow:simple-jndi`, test scope — **not** the abandoned `simple-jndi:simple-jndi` groupId |
|
||
| JUnit Jupiter | `6.0.3` | via `spring-boot-starter-test` |
|
||
| HikariCP | `7.0.2` | pulled in transitively by `spring-boot-starter-data-jpa`; no explicit dependency needed for the Spring-managed chapters |
|
||
| `hibernate-hikaricp` | `7.4.5.Final` | added test-scope for chapter 19's raw, non-Spring `StandardServiceRegistry` bootstrap only |
|
||
| Hibernate Validator | `9.1.3.Final` | what Boot 4.1.1's own BOM manages — confirmed against `spring-boot-dependencies-4.1.1.pom` |
|
||
| `hibernate-validator-cdi` | `9.1.3.Final` | chapter 20 only; not in Boot's BOM, pinned to match |
|
||
| `weld-se-core` | `6.0.4.Final` | chapter 20 only — resolves `jakarta.enterprise.cdi-api:4.1.0` transitively, verified with `mvn dependency:tree` before use |
|
||
| `org.glassfish.expressly` | `6.0.0` | chapter 20 only — the EL implementation matching the `jakarta.el-api:6.0.1` Weld pulls in |
|
||
| `hibernate-search-mapper-orm` | `8.4.0.Final` | chapter 25 — verified against `maven-metadata.xml` as the current GA line, not the `7.3.2.Final` this repo's own earlier post claimed; depends on `hibernate-core:7.4.0.Final`, compatible with this repo's `7.4.5.Final` pin |
|
||
| `hibernate-search-backend-lucene` | `8.4.0.Final` | chapter 25 — the embedded, local-filesystem search backend; pulls in `lucene-core:9.12.3` transitively |
|
||
|
||
**This repo was bumped this session from Boot `4.1.0` / Hibernate `7.4.1.Final` to Boot `4.1.1` /
|
||
Hibernate `7.4.5.Final`.** If you see either of those older numbers anywhere outside
|
||
`docs/00-versions.md`'s own explanation of the bump, that's stale and should be corrected — the
|
||
live `pom.xml` and every chapter added or touched this session already reflect `4.1.1` /
|
||
`7.4.5.Final`.
|
||
|
||
See [`docs/00-versions.md`](docs/00-versions.md) for how these were verified (against
|
||
`maven-metadata.xml`, not Maven Central's search index) and the trap worth knowing about if you
|
||
bump the Spring Boot version again: two different Boot 4.1.x patch releases can resolve two
|
||
different Hibernate patch releases from the same "4.1" line.
|
||
|
||
## Quickstart
|
||
|
||
```bash
|
||
git clone https://ankurm.com/git.app/asmhatre/hibernate-demo.git
|
||
cd hibernate-demo
|
||
./mvnw test
|
||
```
|
||
|
||
Requires JDK 25 and a network connection the first time (Maven needs to fetch plugins online
|
||
before `-o` offline mode works for subsequent runs). `mvn test` runs the full suite — **209
|
||
tests as of the last commit, 2 known errors** (see "Known issues" below; both predate this
|
||
batch) — and takes a couple of minutes, since it boots Hibernate against H2, HSQLDB and Derby
|
||
repeatedly, spins up a real embedded Tomcat for the OSIV chapter, boots a standalone Weld SE CDI
|
||
container for the validation chapter, boots a Lucene-backed Hibernate Search index for every
|
||
single test in the suite (chapter 25's `@Indexed` entity lives in the normally-scanned package,
|
||
so its backend starts once per JVM alongside everything else), and runs a 5,500-iteration timing
|
||
comparison for the
|
||
named-query chapter.
|
||
|
||
Three configuration decisions in this repo are easy to trip over if you're extending it rather
|
||
than just reading it:
|
||
|
||
- **`hibernate.cache.use_second_level_cache: false`** is pinned explicitly in
|
||
[`application.yml`](src/main/resources/application.yml), on purpose. `hibernate-jcache` is on
|
||
this project's classpath (chapter 06's natural-id L2 measurements need it), and Hibernate
|
||
7.4.5 turns the second-level cache **on by itself**, for every context in the repo, the moment
|
||
it finds a `RegionFactory` via the service loader — with nothing configured anywhere. Before
|
||
this was pinned, that silently broke an unrelated test (see
|
||
[chapter 09](docs/09-testing-in-memory-databases.md#hibernate-jcache-on-the-classpath-turns-on-l2-for-everyone-whether-you-asked-or-not)
|
||
for the verbatim failure and the `JCacheOnClasspathAutoEnablesL2Test` that pins it down). If
|
||
you add a JCache/Ehcache/Infinispan dependency to a Hibernate project for one narrow purpose,
|
||
assume it just turned L2 caching on globally unless you pin this back down yourself.
|
||
- **`hibernate-community-dialects` is a required runtime dependency**, not an optional add-on,
|
||
because `org.hibernate.dialect.DerbyDialect` no longer exists in `hibernate-core` as of
|
||
Hibernate 6.2+. Derby's dialect moved to a different package,
|
||
`org.hibernate.community.dialect.DerbyDialect`, in this separate artifact — see
|
||
[chapter 09](docs/09-testing-in-memory-databases.md#headline-correction-derby-has-no-dialect-in-hibernate-7-without-an-extra-dependency)
|
||
for both failure messages this produces if the dependency or the dialect setting is missing.
|
||
- **`hibernate.search.backend.directory.root: target/lucene-indexes`** is pinned explicitly
|
||
because chapter 25's `@Indexed` entity lives in this repo's normally-scanned package tree, so
|
||
Hibernate Search bootstraps for **every** `@SpringBootTest` in the whole suite, not only
|
||
chapter 25's own tests — confirmed the hard way, by watching an already-passing, unrelated test
|
||
fail until this was configured. Adding an `@Indexed` entity to a Spring Boot app means
|
||
configuring a search backend for the whole application, whether or not most of it ever searches
|
||
anything. See [chapter 25](docs/25-hibernate-search.md#two-configuration-traps-that-break-the-whole-application-not-just-this-chapter).
|
||
|
||
## Three databases, and why
|
||
|
||
H2, HSQLDB and Derby are all exercised side by side (chapter 09 in particular boots all three
|
||
against the identical entity mapping), specifically to find where their dialect emulation
|
||
actually diverges rather than repeating folklore about it — the reserved-word survey, the
|
||
CHAR-padding behavior, and the Derby dialect relocation above are all things that only showed up
|
||
by running all three, not by reading about one of them. **Testcontainers is discussed but not
|
||
runnable in the sandbox this repo was built in** — there is no Docker binary and no
|
||
`/var/run/docker.sock` available, so nothing Testcontainers-based was attempted or claimed to
|
||
have been run. The in-memory engines cover fast, unit-level ORM testing; a real production
|
||
database via Testcontainers is a separate, slower integration stage this repo doesn't attempt to
|
||
substitute for.
|
||
|
||
## Chapter index
|
||
|
||
| Chapter | Covers |
|
||
|---|---|
|
||
| [00 — Versions](docs/00-versions.md) | Verified version pins, and the Spring Boot patch that silently changes which Hibernate patch you get |
|
||
| [01 — get() vs getReference()](docs/01-get-vs-load.md) | The 4-calls-4-outcomes table, the same-session matrix, proxy identity vs `equals()` |
|
||
| [02 — merge() vs refresh()](docs/02-merge-vs-refresh.md) | Which method fails loudly vs silently, exactly when the optimistic-lock check fires, and what a cascaded LAZY collection does under `merge()` |
|
||
| [03 — Hibernate 7 batch inserts](docs/03-inserting-objects.md) | `IDENTITY` vs `SEQUENCE`, the allocationSize and batch_size sweeps, `Session` vs `StatelessSession` |
|
||
| [04 — Annotations vs. XML mappings](docs/04-annotations-vs-xml.md) | `hbm.xml` still works (WARN, not broken), `orm.xml` can define a whole entity, XML always wins on conflict, and the third XML dialect (`mapping.xml`) neither older article mentions |
|
||
| [05 — JPA persistence annotations](docs/05-jpa-persistence-annotations.md) | `@Temporal`'s formal deprecation, the ORDINAL enum reorder failure reproduced, `@JdbcTypeCode(JSON)`'s hidden Jackson dependency, the surrogate-id `HashSet` trap, mixed access-type gotchas, and what's actually new in Jakarta Persistence 3.2 |
|
||
| [06 — Natural IDs](docs/06-natural-ids.md) | `bySimpleNaturalId`, L1 vs L2 cache behavior measured with real query counts, the "L2 populates on INSERT, not first lookup" surprise, enforced natural-id immutability, and composite natural ids |
|
||
| [07 — Immutable entities](docs/07-immutable-entities.md) | `@Immutable`'s actual mechanism (dirty-check exclusion, not a write guard), what it does and doesn't block, and a measured flush-cost comparison against `setReadOnly()` |
|
||
| [08 — Stored procedures](docs/08-stored-procedures.md) | IN/OUT/INOUT against a real HSQLDB procedure, a genuine HSQLDB-driver result-set incompatibility, the parameter name-vs-position trap, and why procedure calls don't auto-flush |
|
||
| [09 — Testing with in-memory databases](docs/09-testing-in-memory-databases.md) | Derby's relocated dialect, the `hibernate-jcache` classpath-pollution trap, the real (and not-Derby-exclusive) cross-database divergences, and schema/test isolation strategies |
|
||
| [10 — Mocking JNDI datasources](docs/10-mocking-jndi-datasources.md) | Why `SimpleNamingContextBuilder` is gone, getting `simple-jndi` 0.25.0 actually working, the failure modes verbatim, and whether mock JNDI is still the right answer in 2026 |
|
||
| [11 — Proxies and lazy initialization](docs/11-proxies-and-lazy-initialization.md) | What a `HibernateProxy` actually is, both `LazyInitializationException` message templates, `fetchgraph` vs `loadgraph` demonstrated, and what OSIV actually masks |
|
||
| [12 — Association mappings](docs/12-association-mappings.md) | N+1 counted exactly, `MultipleBagFetchException` and its fixes, the cartesian-product trap, the `@OneToOne` lazy trap, and cascade/orphanRemoval's real (and not-so-real) failure modes |
|
||
| [13 — Date and time mapping](docs/13-date-and-time-mapping.md) | Every basic temporal type round-tripped, the six `TimeZoneStorageType` constants measured under a JVM zone change, nanosecond rounding vs. truncation across databases, and `hibernate.jdbc.time_zone`'s raw-storage effect |
|
||
| [14 — Named queries](docs/14-named-queries.md) | Startup validation's two different failure modes, Hibernate's extra `@NamedQuery` attributes, `orm.xml` named queries, and a measured (negative) answer to "are named queries faster?" |
|
||
| [15 — HQL queries](docs/15-hql-queries.md) | The column-name-vs-field-name pitfall, `JOIN` vs `JOIN FETCH`, aggregates/pagination, bulk `UPDATE`/`DELETE` bypassing the persistence context, and what each flush mode actually suppresses (including why `GenerationType.IDENTITY` defeats an INSERT-based flush-mode test) |
|
||
| [16 — Criteria API](docs/16-criteria-queries.md) | The real generated static metamodel (`Employee_`/`Department_`) vs. string paths, `root.join()` vs `root.fetch()`, aggregation and subqueries, `CriteriaUpdate`/`CriteriaDelete`, and when Criteria earns its ceremony over HQL |
|
||
| [17 — Bootstrapping EntityManager](docs/17-entitymanager-bootstrap.md) | XML vs. Jakarta Persistence 3.2's `PersistenceConfiguration`, proof that a reused persistence-unit name does not trigger an XML lookup, the corrected `jakarta.persistence.PersistenceException` type, and a measured factory-vs-EntityManager creation cost |
|
||
| [18 — Ehcache 3 L2 cache configuration](docs/18-ehcache-l2-configuration.md) | The `jakarta` classifier re-verified as a JAXB choice, not a JCache namespace switch; query-cache-without-entity-cache measured at zero SQL statements (not N+1); bulk HQL *and* native SQL updates both measured as NOT leaving the cache stale, and why; and the missing-timestamps-region "failure" that's actually just a WARN by default |
|
||
| [19 — HikariCP connection pooling](docs/19-hikaricp-connection-pooling.md) | Confirming Spring Boot 4.1.1's default `DataSource` really is Hikari, a raw non-Spring `StandardServiceRegistry` wired to `hibernate-hikaricp`, pool exhaustion's exact `SQLTransientConnectionException`, and the undocumented 2000ms floor below which `leakDetectionThreshold` is silently disabled |
|
||
| [20 — Hibernate Validator CDI integration](docs/20-hibernate-validator-cdi.md) | `@Inject` inside a `ConstraintValidator` measured both ways: a plain NullPointerException (wrapped in `ValidationException`) with no CDI container, and genuine, working injection through a real Weld SE container wired via `hibernate-validator-cdi`'s `ValidationExtension` |
|
||
| [21 — Aggregate functions](docs/21-aggregate-functions.md) | Empty-result-set aggregates return `NULL`/`0`, never `NoResultException`; `select new` with a Java record; the Criteria API equivalent; and HQL window functions (`row_number()` etc.), present since Hibernate 6.2, not new in 7 |
|
||
| [22 — Sorting](docs/22-sorting.md) | `@OrderBy` naming the property not the column, `@SortNatural`/`@SortComparator` on element collections, the dynamic-sort injection risk and its whitelist fix, Criteria `Order` across a join, null precedence via `jakarta.persistence.criteria.Nulls`, and case-insensitive sorting |
|
||
| [23 — Pagination](docs/23-pagination.md) | `setFirstResult`/`setMaxResults` translating to the dialect's real syntax, `ScrollableResults`, exactly when a `join fetch` does and doesn't fall back to in-memory pagination (and the real `HHH90003004` warning code, not `HHH000104`), keyset pagination, and the total-count-query pattern |
|
||
| [24 — Interceptors](docs/24-interceptors.md) | Implementing `Interceptor` directly now that every method is `default` (and where `EmptyInterceptor` actually went), the state-array-mutation contract, session-scoped vs. globally-registered interceptors, and bulk updates bypassing interceptor callbacks entirely |
|
||
| [25 — Hibernate Search](docs/25-hibernate-search.md) | The real current GA version (`8.4.0.Final`, not `7.3.2.Final`), two bootstrap traps that break the whole application, full-text/keyword/generic field types, fuzzy matching, `@IndexedEmbedded`, and rebuilding the index with `MassIndexer` |
|
||
|
||
## Every surprising claim from chapters 01–03, mapped to a test
|
||
|
||
Each row is one `./mvnw -Dtest=ClassName test` away from reproducing itself.
|
||
|
||
| Test class | Backs post | Proves |
|
||
|---|---|---|
|
||
| [`GetVsGetReferenceTest`](src/test/java/com/ankurm/hibernatedemo/GetVsGetReferenceTest.java) | 4859 (get vs getReference) | The 4-calls-4-outcomes table, the same-session matrix, proxy identity vs `equals()` |
|
||
| [`MergeRefreshTest`](src/test/java/com/ankurm/hibernatedemo/MergeRefreshTest.java) | 4860 (merge vs refresh) | `merge()` returns the pre-existing managed instance; `merge()` initializes a cascaded LAZY collection; `refresh()` silently discards an unflushed edit |
|
||
| [`OptimisticLockTest`](src/test/java/com/ankurm/hibernatedemo/OptimisticLockTest.java) | 4860 (merge vs refresh) | Exactly when `OptimisticLockException` surfaces relative to `merge()`/commit |
|
||
| [`IdentityBatchTest`](src/test/java/com/ankurm/hibernatedemo/IdentityBatchTest.java) | 4861 (batch inserts) | `GenerationType.IDENTITY` disables batching entirely |
|
||
| [`SequenceBatchTest`](src/test/java/com/ankurm/hibernatedemo/SequenceBatchTest.java) | 4861 (batch inserts) | `GenerationType.SEQUENCE` allows real batching |
|
||
| [`AllocationSizeSweepTest`](src/test/java/com/ankurm/hibernatedemo/AllocationSizeSweepTest.java) | 4861 (batch inserts) | `allocationSize` sweep (1, 10, 25, 50) at fixed `batch_size=25` |
|
||
| [`BatchSizeSweepTest`](src/test/java/com/ankurm/hibernatedemo/BatchSizeSweepTest.java) | 4861 (batch inserts) | `batch_size` sweep (1, 10, 25, 50) at fixed `allocationSize=50` |
|
||
|
||
For chapters 04–17, the test classes are linked directly from each chapter rather than
|
||
duplicated here — every source file, test class, and captured output file a chapter discusses is
|
||
a relative link in that chapter.
|
||
|
||
```bash
|
||
./mvnw -Dtest=GetVsGetReferenceTest test
|
||
./mvnw -Dtest=MergeRefreshTest,OptimisticLockTest test
|
||
./mvnw -Dtest=IdentityBatchTest,SequenceBatchTest test
|
||
./mvnw -Dtest=AllocationSizeSweepTest test
|
||
./mvnw -Dtest=BatchSizeSweepTest test
|
||
./mvnw -Dtest=HqlQueryTest test
|
||
./mvnw -Dtest=CriteriaQueryTest test
|
||
./mvnw -Dtest=EntityManagerBootstrapTest test
|
||
./mvnw -Dtest='com.ankurm.hibernatedemo.cache.*Test' test
|
||
./mvnw -Dtest='com.ankurm.hibernatedemo.hikari.*Test' test
|
||
./mvnw -Dtest='com.ankurm.hibernatedemo.validation.*Test' test
|
||
./mvnw -Dtest=AggregateFunctionsTest test
|
||
./mvnw -Dtest=SortingTest test
|
||
./mvnw -Dtest=PaginationTest test
|
||
./mvnw -Dtest=InterceptorTest test
|
||
./mvnw -Dtest=HibernateSearchTest test
|
||
./mvnw test # the whole suite, 209 tests as of the last commit — see "Known issues" below
|
||
```
|
||
|
||
### Known issues
|
||
|
||
**`OrmXmlNamedQueryTest` (chapter 14) currently fails, and it predates chapters 15–17.** Verified
|
||
by stashing every change made for chapters 15–17 and re-running the suite against the unmodified
|
||
tree: the same two errors reproduce identically (`No query named 'XmlQueryEmployee.findBySalaryAboveXml'`
|
||
and `No parameter named ':min' in query with named parameters []`), so this is not a regression
|
||
from the HQL/Criteria/bootstrap work. It contradicts chapter 14's own claim that `orm.xml` named
|
||
queries are "auto-discovered with no `persistence.xml`" under Spring Boot's default JPA
|
||
autoconfiguration — that claim needs re-verification against the current Hibernate/Spring Boot
|
||
versions (this repo was bumped mid-batch from Boot 4.1.0/Hibernate 7.4.1.Final to Boot
|
||
4.1.1/Hibernate 7.4.5.Final, which is one plausible place the behavior changed) before it's
|
||
trusted again. Flagged here rather than fixed silently, since chapter 14 and its post (4877) are
|
||
outside this batch's scope.
|
||
|
||
## CommandLineRunner scenarios
|
||
|
||
The original narrative scenarios (chapters 01–03 only) are still here, unchanged, for anyone who
|
||
wants to read a straight-line script instead of a test class:
|
||
|
||
| Profile | Runs | Chapter |
|
||
|---|---|---|
|
||
| `getvsload` | `session.get()` vs `session.getReference()`, proxies, `LazyInitializationException` | [docs/01-get-vs-load.md](docs/01-get-vs-load.md) |
|
||
| `mergerefresh` | `merge()` vs `refresh()` against a `@Version`-ed entity | [docs/02-merge-vs-refresh.md](docs/02-merge-vs-refresh.md) |
|
||
| `insert-identity` | Batch insert attempt with `GenerationType.IDENTITY` | [docs/03-inserting-objects.md](docs/03-inserting-objects.md) |
|
||
| `insert-sequence` | The same insert, with `GenerationType.SEQUENCE` | [docs/03-inserting-objects.md](docs/03-inserting-objects.md) |
|
||
|
||
```bash
|
||
./scripts/run.sh getvsload
|
||
./scripts/run.sh mergerefresh
|
||
./scripts/run.sh insert-identity
|
||
./scripts/run.sh insert-sequence
|
||
```
|
||
|
||
Chapters 04–17 don't have `CommandLineRunner` profiles — they're covered entirely by JUnit tests
|
||
and `javap`/`unzip` probes, captured the same way (see below).
|
||
|
||
## Regenerating captured output
|
||
|
||
```bash
|
||
./scripts/run-all.sh
|
||
```
|
||
|
||
Regenerates the `CommandLineRunner`-scenario files in `docs/output/` (chapters 01–03 only).
|
||
`scripts/clean_output.py` strips JVM noise and a harmless duplicate SQL echo line so the
|
||
committed transcripts stay readable — nothing else is edited by hand. Every other transcript in
|
||
`docs/output/` (chapters 04–17, and the test-suite transcripts for 01–03) was captured directly
|
||
from `./mvnw -Dtest=... test`, `javap`, or `unzip -l` piped through the same cleanup approach, not
|
||
regenerated by a single script — see each chapter for the exact command that produced its output.
|
||
|
||
## Output index
|
||
|
||
`docs/output/` holds 101 raw, unedited transcripts, grouped here by topic prefix.
|
||
|
||
| Prefix | Files | What it captures |
|
||
|---|---|---|
|
||
| `get-vs-*` | 2 | Chapter 01: the `CommandLineRunner` scenario and the `GetVsGetReferenceTest` run |
|
||
| `merge-vs-refresh*` | 2 | Chapter 02: the `CommandLineRunner` scenario and the `MergeRefreshTest`/`OptimisticLockTest` run |
|
||
| `insert-*` | 2 | Chapter 03: the identity vs. sequence `CommandLineRunner` scenarios |
|
||
| `allocation-and-batch-size-sweeps.txt` | 1 | Chapter 03: the allocationSize and batch_size sweep test run |
|
||
| `mappingstyle-*` | 1 | Chapter 04: the full `hbm.xml`/`orm.xml`/`mapping.xml` test run |
|
||
| `persistenceannotations-*` | 1 | Chapter 05: the full persistence-annotations test run |
|
||
| `naturalid-*` | 1 | Chapter 06: the full natural-id L1/L2/mutability/composite test run |
|
||
| `immutable-*` | 2 | Chapter 07: the `@Immutable` behavior run, and the `javap` capture of the annotation itself |
|
||
| `procedure-*` | 4 | Chapter 08: happy-path and failure-mode runs, the HSQLDB driver quirk reproduction, and the `javap` API-surface capture |
|
||
| `testdb-*` | 9 | Chapter 09: dialect resolution, DDL generation, the reserved-word survey, cross-database behavior, schema isolation, startup timing, the Derby dialect failure, and the jcache classpath-pollution failure |
|
||
| `jndi-*` | 6 | Chapter 10: the `SimpleNamingContextBuilder` removal proof, the simple-jndi jar listing, Boot's JNDI autoconfigure `javap` capture, Hibernate's own JNDI datasource `javap` capture, and both the filtered and unfiltered full test runs |
|
||
| `proxy-*` | 7 | Chapter 11: proxy identity and `LazyInitializationException` (filtered and raw), entity-graph fetch behavior (filtered and raw), OSIV masking (filtered and raw), and the `javap` capture of proxy-related settings |
|
||
| `association-*` | 4 | Chapter 12: N+1 counting, the multiple-bag-fetch/cartesian-product runs, the `@OneToOne` lazy trap, and cascade/orphanRemoval |
|
||
| `datetime-*` | 7 | Chapter 13: basic temporal round trips, the `@Temporal` deprecation warning, both `@TimeZoneStorage` JVM-zone runs, nanosecond rounding on both H2 and HSQLDB, and `hibernate.jdbc.time_zone` |
|
||
| `namedquery-*` | 4 | Chapter 14: startup validation, execution/projections, `orm.xml` named queries, and the pre-parsing performance comparison |
|
||
| `hql-*` | 3 | Chapter 15: select/join pitfalls, aggregation/paging/bulk operations, and flush-mode behavior |
|
||
| `criteria-*` | 3 | Chapter 16: predicates and the static metamodel, aggregation/subqueries, and bulk update/delete |
|
||
| `bootstrap-persistenceconfiguration.txt` | 1 | Chapter 17: XML and programmatic bootstrap, the persistence-unit name-collision proof, the unconfigured-name exception, and the factory-creation timing |
|
||
| `18-*` | 7 | Chapter 18: the JCache-namespace re-verification, entity L2 caching, query-cache-without-entity-cache, bulk HQL and native SQL update cache behavior, and both missing-timestamps-region runs (default and strict) |
|
||
| `19-*` | 4 | Chapter 19: confirming Spring Boot's default `DataSource` is Hikari, the raw non-Spring bootstrap, pool exhaustion, and both leak-detection runs (the sub-2000ms silent-disable trap and a real leak caught at the floor) |
|
||
| `20-*` | 2 | Chapter 20: `@Inject` failing with a wrapped NullPointerException under plain Bean Validation, and working correctly inside a running Weld SE container |
|
||
| `21-*` | 4 | Chapter 21: empty-result-set aggregates, `select new` record construction under GROUP BY/HAVING, the Criteria API `avg()` equivalent, and the `row_number()` window function |
|
||
| `22-*` | 6 | Chapter 22: `@OrderBy` property-vs-column resolution, `@SortNatural`/`@SortComparator`, the dynamic-sort injection guard, Criteria `Order` across a join, null precedence, and case-insensitive sorting |
|
||
| `23-*` | 6 | Chapter 23: `LIMIT`/`OFFSET` translation, `ScrollableResults`, both join-fetch-pagination scenarios (root-ordered vs. collection-ordered), keyset pagination, and the total-count-query pattern |
|
||
| `24-*` | 4 | Chapter 24: session-scoped interceptor state mutation, interceptor scoping, global registration via `hibernate.session_factory.interceptor`, and bulk updates bypassing interceptor callbacks |
|
||
| `25-*` | 5 | Chapter 25: fuzzy full-text matching, exact keyword-field matching, sortable generic fields, `@IndexedEmbedded` association search, and `MassIndexer` index rebuilding |
|
||
|
||
## Layout
|
||
|
||
```
|
||
hibernate-demo/
|
||
├── pom.xml
|
||
├── LICENSE
|
||
├── scripts/
|
||
│ ├── run.sh start one CommandLineRunner profile, run it, exit
|
||
│ ├── run-all.sh regenerate the CommandLineRunner docs/output/ files
|
||
│ ├── clean_output.py strip JVM noise + a duplicate SQL echo line from a raw capture
|
||
│ └── check_links.py walk docs/*.md and verify every relative link resolves on disk
|
||
├── src/main/java/com/ankurm/hibernatedemo/
|
||
│ ├── HibernateDemoApplication.java
|
||
│ ├── model/ Book, Note, Widget* entities (chapters 01–03)
|
||
│ ├── scenario/ one CommandLineRunner per profile (chapters 01–03)
|
||
│ ├── mappingstyle/ chapter 04 entities
|
||
│ ├── persistenceannotations/ chapter 05 entities
|
||
│ ├── naturalid/ chapter 06 entities
|
||
│ ├── immutable/ chapter 07 entities
|
||
│ ├── procedure/ chapter 08 entities
|
||
│ ├── testdb/ chapter 09 entity
|
||
│ ├── proxy/ chapter 11 entities
|
||
│ ├── association/ chapter 12 entities
|
||
│ ├── datetime/ chapter 13 entities
|
||
│ ├── namedquery/ chapter 14 entities
|
||
│ ├── query/ chapters 15–16 entities (Employee, Department — @Entity(name="QueryDept"))
|
||
│ ├── bootstrap/ chapter 17 entity (BootstrapUser)
|
||
│ ├── cache/ chapter 18 entities (CacheProduct, UncachedProduct)
|
||
│ ├── hikari/ chapter 19 entity (PoolProbe)
|
||
│ ├── validation/ chapter 20 classes (InventoryPolicy, PositiveInventory,
|
||
│ │ PositiveInventoryValidator, StockLevel) -- not JPA entities
|
||
│ ├── aggregate/ chapter 21 entities (Product, CategorySummary record)
|
||
│ ├── sorting/ chapter 22 entities (Playlist, Song, LengthThenAlphaComparator,
|
||
│ │ SongSortField)
|
||
│ ├── pagination/ chapter 23 entities (Article, Comment)
|
||
│ ├── interceptor/ chapter 24 entity + interceptor (Task, UppercasingInterceptor)
|
||
│ └── search/ chapter 25 entities (Movie, Director) -- @Indexed, on the
|
||
│ normally-scanned package tree; see README "Quickstart" above
|
||
├── src/test/java/com/ankurm/
|
||
│ ├── brokenprobe/ a deliberately broken entity kept outside the scanned package (chapter 14)
|
||
│ └── hibernatedemo/
|
||
│ ├── GetVsGetReferenceTest.java, MergeRefreshTest.java, OptimisticLockTest.java,
|
||
│ │ IdentityBatchTest.java, SequenceBatchTest.java, AllocationSizeSweepTest.java,
|
||
│ │ BatchSizeSweepTest.java, ImmutableEntityTest.java, ImmutableBulkUpdateAllowedTest.java,
|
||
│ │ ImmutableFlushCostTest.java (chapters 01–03, 07)
|
||
│ ├── mappingstyle/, persistenceannotations/, naturalid/, procedure/, testdb/,
|
||
│ │ proxy/, association/, datetime/, namedquery/, jndi/ (chapters 04–06, 08–14)
|
||
│ ├── query/ HqlQueryTest.java, CriteriaQueryTest.java (chapters 15–16)
|
||
│ ├── bootstrap/ EntityManagerBootstrapTest.java, plain JUnit, no Spring (chapter 17)
|
||
│ ├── cache/ EntityL2CacheTest, QueryCacheWithoutEntityCacheTest,
|
||
│ │ BulkUpdateBypassesCacheTest, MissingUpdateTimestampsRegionTest,
|
||
│ │ CacheApiNamespaceTest -- all raw StandardServiceRegistry, no Spring (chapter 18)
|
||
│ ├── hikari/ SpringAutoConfiguredHikariTest (Spring), HikariRawBootstrapTest (raw),
|
||
│ │ HikariLeakDetectionTest, HikariPoolExhaustionTest (chapter 19)
|
||
│ ├── validation/ PlainValidationNoCdiTest, CdiValidationTest (Weld SE) (chapter 20)
|
||
│ ├── aggregate/ AggregateFunctionsTest (chapter 21)
|
||
│ ├── sorting/ SortingTest (chapter 22)
|
||
│ ├── pagination/ PaginationTest (chapter 23)
|
||
│ ├── interceptor/ InterceptorTest (chapter 24)
|
||
│ └── search/ HibernateSearchTest (chapter 25)
|
||
└── docs/
|
||
├── 00-versions.md .. 25-hibernate-search.md
|
||
└── output/*.txt captured, unedited console transcripts (101 files)
|
||
```
|
||
|
||
## License
|
||
|
||
MIT — see [LICENSE](LICENSE).
|