Add Hibernate 7 batches 2-5: mapping styles, JPA annotations, natural IDs, @Immutable, stored procedures, in-memory test databases, JNDI mocking, proxies, associations, temporal mapping and named queries (Hibernate 7.4.5.Final + Spring Boot 4.1.1 + JDK 25)
This commit is contained in:
Executable
+6
@@ -0,0 +1,6 @@
|
||||
target/
|
||||
*.class
|
||||
.idea/
|
||||
*.iml
|
||||
.vscode/
|
||||
.DS_Store
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Ankur Mhatre
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,230 @@
|
||||
# hibernate-demo
|
||||
|
||||
Companion repository for a batch of fifteen 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), and 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). 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` |
|
||||
|
||||
**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 — **141
|
||||
tests, 0 failures** as of the last commit — 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, and runs a 5,500-iteration timing comparison for the named-query chapter.
|
||||
|
||||
Two 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.
|
||||
|
||||
## 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?" |
|
||||
|
||||
## 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–14, 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 test # the whole suite, 141 tests, 0 failures as of the last commit
|
||||
```
|
||||
|
||||
## 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–14 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–14, 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 56 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 |
|
||||
|
||||
## 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
|
||||
├── 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)
|
||||
└── docs/
|
||||
├── 00-versions.md .. 14-named-queries.md
|
||||
└── output/*.txt captured, unedited console transcripts (56 files)
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT — see [LICENSE](LICENSE).
|
||||
@@ -0,0 +1,78 @@
|
||||
----------------------------------------------------------------
|
||||
Sun Sep 06 10:27:55 IST 2026:
|
||||
Booting Derby version The Apache Software Foundation - Apache Derby - 10.16.1.1 - (1901046): instance a816c00e-01a0-7514-8b9f-0000031bffd0
|
||||
on database directory memory:/tmp/work/testdb-timing0 with class loader jdk.internal.loader.ClassLoaders$AppClassLoader@7c84929b
|
||||
Loaded from file:/sessions/intelligent-loving-cori/.m2/repository/org/apache/derby/derby/10.16.1.1/derby-10.16.1.1.jar
|
||||
java.vendor=Eclipse Adoptium
|
||||
java.runtime.version=25.0.4.1+1-LTS
|
||||
user.dir=/tmp/work
|
||||
os.name=Linux
|
||||
os.arch=amd64
|
||||
os.version=6.8.0-136-generic
|
||||
derby.system.home=null
|
||||
Database Class Loader started - derby.database.classpath=''
|
||||
----------------------------------------------------------------
|
||||
Sun Sep 06 10:27:56 IST 2026:
|
||||
Booting Derby version The Apache Software Foundation - Apache Derby - 10.16.1.1 - (1901046): instance 42adc10b-01a0-7514-8b9f-0000031bffd0
|
||||
on database directory memory:/tmp/work/testdb-timing1 with class loader jdk.internal.loader.ClassLoaders$AppClassLoader@7c84929b
|
||||
Loaded from file:/sessions/intelligent-loving-cori/.m2/repository/org/apache/derby/derby/10.16.1.1/derby-10.16.1.1.jar
|
||||
java.vendor=Eclipse Adoptium
|
||||
java.runtime.version=25.0.4.1+1-LTS
|
||||
user.dir=/tmp/work
|
||||
os.name=Linux
|
||||
os.arch=amd64
|
||||
os.version=6.8.0-136-generic
|
||||
derby.system.home=null
|
||||
Database Class Loader started - derby.database.classpath=''
|
||||
----------------------------------------------------------------
|
||||
Sun Sep 06 10:27:56 IST 2026:
|
||||
Booting Derby version The Apache Software Foundation - Apache Derby - 10.16.1.1 - (1901046): instance bbc70208-01a0-7514-8b9f-0000031bffd0
|
||||
on database directory memory:/tmp/work/testdb-timing2 with class loader jdk.internal.loader.ClassLoaders$AppClassLoader@7c84929b
|
||||
Loaded from file:/sessions/intelligent-loving-cori/.m2/repository/org/apache/derby/derby/10.16.1.1/derby-10.16.1.1.jar
|
||||
java.vendor=Eclipse Adoptium
|
||||
java.runtime.version=25.0.4.1+1-LTS
|
||||
user.dir=/tmp/work
|
||||
os.name=Linux
|
||||
os.arch=amd64
|
||||
os.version=6.8.0-136-generic
|
||||
derby.system.home=null
|
||||
Database Class Loader started - derby.database.classpath=''
|
||||
----------------------------------------------------------------
|
||||
Sun Sep 06 10:27:56 IST 2026:
|
||||
Booting Derby version The Apache Software Foundation - Apache Derby - 10.16.1.1 - (1901046): instance 63628305-01a0-7514-8b9f-0000031bffd0
|
||||
on database directory memory:/tmp/work/testdb-reservedword with class loader jdk.internal.loader.ClassLoaders$AppClassLoader@7c84929b
|
||||
Loaded from file:/sessions/intelligent-loving-cori/.m2/repository/org/apache/derby/derby/10.16.1.1/derby-10.16.1.1.jar
|
||||
java.vendor=Eclipse Adoptium
|
||||
java.runtime.version=25.0.4.1+1-LTS
|
||||
user.dir=/tmp/work
|
||||
os.name=Linux
|
||||
os.arch=amd64
|
||||
os.version=6.8.0-136-generic
|
||||
derby.system.home=null
|
||||
Database Class Loader started - derby.database.classpath=''
|
||||
----------------------------------------------------------------
|
||||
Sun Sep 06 10:27:56 IST 2026:
|
||||
Booting Derby version The Apache Software Foundation - Apache Derby - 10.16.1.1 - (1901046): instance 5d8dc3f6-01a0-7514-8b9f-0000031bffd0
|
||||
on database directory memory:/tmp/work/testdb-charpad with class loader jdk.internal.loader.ClassLoaders$AppClassLoader@7c84929b
|
||||
Loaded from file:/sessions/intelligent-loving-cori/.m2/repository/org/apache/derby/derby/10.16.1.1/derby-10.16.1.1.jar
|
||||
java.vendor=Eclipse Adoptium
|
||||
java.runtime.version=25.0.4.1+1-LTS
|
||||
user.dir=/tmp/work
|
||||
os.name=Linux
|
||||
os.arch=amd64
|
||||
os.version=6.8.0-136-generic
|
||||
derby.system.home=null
|
||||
Database Class Loader started - derby.database.classpath=''
|
||||
----------------------------------------------------------------
|
||||
Sun Sep 06 10:27:57 IST 2026:
|
||||
Booting Derby version The Apache Software Foundation - Apache Derby - 10.16.1.1 - (1901046): instance 2559c4eb-01a0-7514-8b9f-0000031bffd0
|
||||
on database directory memory:/tmp/work/testdb-plain with class loader jdk.internal.loader.ClassLoaders$AppClassLoader@7c84929b
|
||||
Loaded from file:/sessions/intelligent-loving-cori/.m2/repository/org/apache/derby/derby/10.16.1.1/derby-10.16.1.1.jar
|
||||
java.vendor=Eclipse Adoptium
|
||||
java.runtime.version=25.0.4.1+1-LTS
|
||||
user.dir=/tmp/work
|
||||
os.name=Linux
|
||||
os.arch=amd64
|
||||
os.version=6.8.0-136-generic
|
||||
derby.system.home=null
|
||||
Database Class Loader started - derby.database.classpath=''
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
# 00 — Versions
|
||||
|
||||
[Next: 01 — get() vs load() →](01-get-vs-load.md)
|
||||
|
||||
This repository is pinned to:
|
||||
|
||||
| Component | Version | GA date | Source |
|
||||
|---|---|---|---|
|
||||
| Spring Boot | `4.1.1` | 2026-07 | [spring.io/blog](https://spring.io/blog/) |
|
||||
| Hibernate ORM | `7.4.5.Final` | — | resolved by Spring Boot 4.1.1's dependency management |
|
||||
| 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) | 2025-09 | latest LTS at the time this repo was built |
|
||||
| H2 | `2.4.240` | — | in-memory, `DB_CLOSE_DELAY=-1` |
|
||||
| HSQLDB | `2.7.3` | — | in-memory |
|
||||
| Apache Derby | `10.16.1.1` | — | in-memory; dialect lives in `hibernate-community-dialects`, not `hibernate-core` |
|
||||
| simple-jndi | `0.25.0` | — | `com.github.h-thurow:simple-jndi`, test scope (the `simple-jndi:simple-jndi` groupId is an abandoned fork — don't use it) |
|
||||
| JUnit Jupiter | `6.0.3` | — | via `spring-boot-starter-test` |
|
||||
|
||||
## The pin was deliberately bumped mid-batch: `4.1.0`/`7.4.1.Final` → `4.1.1`/`7.4.5.Final`
|
||||
|
||||
Earlier chapters in this repository (00–03) were originally written and verified against Spring
|
||||
Boot `4.1.0`, which resolves Hibernate ORM `7.4.1.Final`. This repository has since been bumped
|
||||
to Spring Boot `4.1.1`, which resolves a *different* Hibernate patch, `7.4.5.Final` — four
|
||||
Hibernate patch releases ahead, from the same "4.1" Spring Boot minor line. Every chapter added
|
||||
this session (04–14), and this file, are verified against the new pin: `7.4.5.Final`. If you spot
|
||||
`7.4.1.Final` or Spring Boot `4.1.0` anywhere in this repository outside of this historical note,
|
||||
that is stale and should be corrected.
|
||||
|
||||
This is worth explaining precisely, because the mechanism is the same one that could bite you on
|
||||
your *next* bump, not just the one already made.
|
||||
|
||||
Checking `spring-boot-dependencies-4.1.0.pom` directly showed
|
||||
`<hibernate.version>7.4.1.Final</hibernate.version>` — so on Boot 4.1.0, this repo's `pom.xml`
|
||||
did not need to override anything to get 7.4.1.Final; the `<hibernate.version>` property was
|
||||
redundant with what Boot already resolved, kept only so the pin was visible without cracking open
|
||||
Boot's own POM.
|
||||
|
||||
That stopped being true one patch release later. `spring-boot-dependencies-4.1.1.pom` resolves
|
||||
`hibernate.version` to `7.4.5.Final` — a different Hibernate patch from the same Spring Boot
|
||||
minor version, four Hibernate patch releases apart. Bumping this repo's parent to `4.1.1`
|
||||
*without* also updating the `<hibernate.version>` property in `pom.xml` would have silently kept
|
||||
`7.4.1.Final` (the explicit property would have overridden Boot's own management) instead of the
|
||||
`7.4.5.Final` Boot actually intends for that release — which is exactly the trap this repo avoids
|
||||
by keeping the property in lockstep with whatever Boot version is pinned, rather than treating it
|
||||
as a one-time, set-and-forget value.
|
||||
|
||||
| Spring Boot version | Hibernate version Boot resolves |
|
||||
|---|---|
|
||||
| `4.0.8` | `7.2.24.Final` |
|
||||
| `4.1.0` | `7.4.1.Final` |
|
||||
| `4.1.1` | `7.4.5.Final` |
|
||||
|
||||
The lesson generalizes past this one bump: **never assume a Spring Boot patch release leaves
|
||||
Hibernate's patch version untouched.** Two Boot releases that look adjacent by patch number
|
||||
("4.1.0" vs "4.1.1") can be four Hibernate patch releases apart. Always re-check
|
||||
`spring-boot-dependencies-<version>.pom` directly (or run a `mvn dependency:tree` /
|
||||
`dependency:resolve` against the new parent) after any Boot version bump, rather than assuming
|
||||
last time's Hibernate pin still applies.
|
||||
|
||||
## Databases and other dependencies added since the original three-chapter batch
|
||||
|
||||
Chapters 04–14 exercise three JDBC databases side by side, plus a handful of dependencies none
|
||||
of chapters 00–03 needed:
|
||||
|
||||
| Component | Version | Why it's here |
|
||||
|---|---|---|
|
||||
| H2 | `2.4.240` | primary in-memory database for most chapters |
|
||||
| HSQLDB | `2.7.3` | genuine SQL/PSM stored procedures (chapter 08); cross-database comparison (chapter 09) |
|
||||
| Apache Derby (`derby` + `derbytools`) | `10.16.1.1` | cross-database comparison (chapter 09) |
|
||||
| `hibernate-community-dialects` | `7.4.5.Final` | **required**, not optional — `DerbyDialect` was removed from `hibernate-core` in Hibernate 6.2+ and now lives here, under `org.hibernate.community.dialect` |
|
||||
| `com.github.h-thurow:simple-jndi` | `0.25.0` | mocking a JNDI `DataSource` without a real container (chapter 10) — test scope only |
|
||||
| `tools.jackson.core:jackson-databind` | managed by Boot's BOM | required for `@JdbcTypeCode(SqlTypes.JSON)` to work at all (chapter 05) — `spring-boot-starter-data-jpa` alone does not pull in a JSON mapper |
|
||||
| `hibernate-jcache` + `javax.cache:cache-api` + `org.ehcache:ehcache` (`jakarta` classifier) | `7.4.5.Final` / `1.1.1` / `3.10.8` | measuring `@NaturalIdCache` L2 behavior with real numbers (chapter 06) — see chapter 09 for the classpath-pollution side effect this has on *every other test in the repo*, which is why `hibernate.cache.use_second_level_cache: false` is pinned explicitly in `application.yml` |
|
||||
|
||||
## Verified against `maven-metadata.xml`, not Maven Central's search index
|
||||
|
||||
Verified against `maven-metadata.xml` on `repo1.maven.org`, not against Maven Central's
|
||||
`solrsearch` API — that index has been observed stale from this kind of sandboxed build
|
||||
environment (it reported an old Spring Boot release as newest well after a later one had
|
||||
shipped), so it should not be trusted for currency checks.
|
||||
|
||||
[Next: 01 — get() vs load() →](01-get-vs-load.md)
|
||||
Executable
+134
@@ -0,0 +1,134 @@
|
||||
# 01 — get() vs getReference()
|
||||
|
||||
[← Previous: 00 — Versions](00-versions.md) | [Next: 02 — merge() vs refresh() →](02-merge-vs-refresh.md)
|
||||
|
||||
Backs [ankurm.com: Hibernate 7 — get() vs load()](https://ankurm.com/hibernate-7-get-vs-load-which-one-should-you-actually-use/).
|
||||
|
||||
Test class: [`GetVsGetReferenceTest`](../src/test/java/com/ankurm/hibernatedemo/GetVsGetReferenceTest.java).
|
||||
Run it yourself:
|
||||
|
||||
```bash
|
||||
git clone https://ankurm.com/git.app/asmhatre/hibernate-demo.git
|
||||
cd hibernate-demo
|
||||
./mvnw -Dtest=GetVsGetReferenceTest test
|
||||
```
|
||||
|
||||
Every number and exception class name below came from that command, not from documentation or
|
||||
memory. Raw captured output: [`docs/output/get-vs-getreference-tests.txt`](output/get-vs-getreference-tests.txt).
|
||||
|
||||
## Contract vs observation
|
||||
|
||||
The JPA/Hibernate contract for these two methods is short: `get()` fetches now and may return
|
||||
`null`; `getReference()` defers and may throw once accessed. That contract is real and both
|
||||
methods honor it. What it doesn't tell you is what happens once the *same id* has already been
|
||||
touched once in the *same session* — and that's where the interesting behavior lives, because it's
|
||||
governed by the persistence context, not by the method you happen to call second.
|
||||
|
||||
## Mental model
|
||||
|
||||
Stop thinking of `get()` vs `getReference()` as "eager vs lazy." Think of it as what you're telling
|
||||
Hibernate you need:
|
||||
|
||||
- `get()` says **"I need the entity."** Hibernate will do whatever it takes — including firing a
|
||||
`SELECT` against an id it already has a reference for — to hand you something with real data
|
||||
behind it.
|
||||
- `getReference()` says **"I need a reference."** Hibernate will hand you the cheapest possible
|
||||
object that satisfies that and defers everything else, including telling you the row doesn't
|
||||
exist.
|
||||
|
||||
That framing predicts the session-matrix results in the next section better than "eager vs lazy"
|
||||
does — see the `getReference()` → `get()` row in particular.
|
||||
|
||||
## Four calls, four outcomes
|
||||
|
||||
| # | Call | Fires a `SELECT` at the call site? | Row missing | Row exists |
|
||||
|---|---|---|---|---|
|
||||
| 1 | `session.get(Book.class, id)` | Yes, immediately | returns `null` | returns the real entity |
|
||||
| 2 | `session.get(Book.class, id)` (missing id) | Yes, immediately | returns `null` | — |
|
||||
| 3 | `session.getReference(Book.class, id)` | No — deferred to first non-id accessor | proxy returned, no error yet | proxy returned, no `SELECT` yet |
|
||||
| 4 | `session.getReference(Book.class, id)` (missing id), then `.getTitle()` | Yes, on first accessor call | throws `jakarta.persistence.EntityNotFoundException` on access | — |
|
||||
|
||||
Row 4 is worth being precise about: the exception class is `jakarta.persistence.EntityNotFoundException`,
|
||||
not `org.hibernate.ObjectNotFoundException` — the name still used in a lot of older Hibernate
|
||||
discussion. Running it against 7.4.1.Final settles which one this version actually throws.
|
||||
|
||||
## Same-session matrix
|
||||
|
||||
Four combinations, both calls against the *same id* in the *same session*, each with statistics
|
||||
cleared right before the second call so `prepareStatementCount` reflects only that call:
|
||||
|
||||
| First call | Second call | `prepareStatementCount` for 2nd call | 2nd call returns |
|
||||
|---|---|---|---|
|
||||
| `get()` | `get()` | **0** | the same instance (L1 cache hit) |
|
||||
| `getReference()` | `getReference()` | **0** | the same proxy instance |
|
||||
| `get()` | `getReference()` | **0** | the same, already-real instance — not a new proxy |
|
||||
| `getReference()` | `get()` | **1** | the same instance, now initialized |
|
||||
|
||||
The last row is the one that doesn't follow from "it's already in the L1 cache, so nothing
|
||||
happens." It does happen: calling `get()` against an id that already has an *uninitialized* proxy
|
||||
sitting in the persistence context still fires a `SELECT`. `get()`'s contract is "hand back a real,
|
||||
usable entity" — an uninitialized proxy doesn't satisfy that, so Hibernate initializes it in place
|
||||
and returns the same object reference, now with real data behind it. The reverse direction
|
||||
(`get()` then `getReference()`) needs nothing further, because a real, fully-loaded instance
|
||||
already satisfies whatever `getReference()` was going to ask for.
|
||||
|
||||
This wasn't something I went looking for — it fell out of writing the fourth row of the matrix
|
||||
and reading the log, which is the actual argument for building the matrix instead of reasoning
|
||||
about two of the four cells and assuming the rest.
|
||||
|
||||
## Proxy identity experiment
|
||||
|
||||
Six checks against the same proxy, all in one test:
|
||||
|
||||
```java
|
||||
assertThat(proxy).isInstanceOf(Book.class); // true
|
||||
assertThat(Hibernate.getClass(proxy)).isEqualTo(Book.class); // true -- the REAL class
|
||||
assertThat(proxy.getClass()).isNotEqualTo(Book.class); // true -- proxy.getClass() is Book$HibernateProxy
|
||||
assertThat(real.equals(proxy)).isFalse(); // false
|
||||
assertThat(proxy.equals(real)).isFalse(); // false, both directions
|
||||
assertThat(new HashSet<>(List.of(real)).contains(proxy)).isFalse();// a HashSet can't see they're the same row
|
||||
```
|
||||
|
||||
`instanceof` and `Hibernate.getClass()` both see through the proxy to the real type. `getClass()`
|
||||
does not — a Hibernate proxy's runtime class is a generated `Book$HibernateProxy`, never `Book`
|
||||
itself, which is why `Hibernate.getClass()` exists as the "give me the real entity class" escape
|
||||
hatch. `equals()` breaks in both directions because `Book` never overrides it, so Java's default
|
||||
falls back to reference identity — this is not a Hibernate quirk, it's plain Java doing exactly
|
||||
what an un-overridden `equals()` always does once two different objects (a proxy and a loaded
|
||||
instance) represent the same row. The `HashSet` check is the concrete cost of that: a collection
|
||||
built on default `equals()`/`hashCode()` cannot recognize the proxy and the real instance as the
|
||||
same database row, silently.
|
||||
|
||||
A seventh check, in a separate test, confirms the other well-known proxy trap: a proxy that
|
||||
outlives the session that created it throws `org.hibernate.LazyInitializationException` the
|
||||
moment a non-id accessor is called on it — a different failure from `EntityNotFoundException`,
|
||||
worth not confusing with it.
|
||||
|
||||
## What surprised me building this
|
||||
|
||||
Two things, not one.
|
||||
|
||||
The proxy-equals-breaking result was expected going in, just not in its full shape — I expected
|
||||
`equals()` to be asymmetric or to depend on which side calls it. It doesn't; it fails identically
|
||||
in both directions, which is simpler and worse than a half-remembered version of this story
|
||||
usually gets described.
|
||||
|
||||
The one I didn't expect at all was the `getReference()` → `get()` row of the session matrix. The
|
||||
intuitive prediction — "the id is already in the L1 cache, so the second call is free" — is true
|
||||
for three of the four matrix combinations and wrong for exactly this one, because `get()`'s
|
||||
contract requires more than presence in the cache; it requires the object behind that cache entry
|
||||
to actually be usable as loaded data. Predicting three cells right and getting the fourth wrong
|
||||
in a way that only shows up by actually building all four is the whole argument for running the
|
||||
matrix instead of describing two of its cells from memory.
|
||||
|
||||
## Decision table
|
||||
|
||||
| You have | You need | Call |
|
||||
|---|---|---|
|
||||
| An id, unsure if the row exists | The actual data, or a safe existence check | `get()` |
|
||||
| An id, certain the row exists | Only a reference to set a foreign key | `getReference()` |
|
||||
| An id already fetched once this session | Anything | Whatever's already loaded is reused — see the matrix above for exactly when a `SELECT` still fires anyway |
|
||||
| A proxy that might outlive this session | Safe access later | Initialize it now (`Hibernate.initialize(proxy)`), or don't let it leave the session |
|
||||
| Two references to the same row from mixed `get()`/`getReference()` calls, going into a `Set` or `equals()`-based comparison | Correct identity behavior | Override `equals()`/`hashCode()` on the id — the un-overridden default will not survive the proxy boundary |
|
||||
|
||||
[← Previous: 00 — Versions](00-versions.md) | [Next: 02 — merge() vs refresh() →](02-merge-vs-refresh.md)
|
||||
Executable
+170
@@ -0,0 +1,170 @@
|
||||
# 02 — merge() vs refresh()
|
||||
|
||||
[← Previous: 01 — get() vs getReference()](01-get-vs-load.md) | [Next: 03 — Inserting objects →](03-inserting-objects.md)
|
||||
|
||||
Backs [ankurm.com: merge() vs refresh()](https://ankurm.com/mastering-hibernate-7-merging-vs-refreshing-entities-for-robust-data-consistency/).
|
||||
|
||||
Test classes: [`MergeRefreshTest`](../src/test/java/com/ankurm/hibernatedemo/MergeRefreshTest.java),
|
||||
[`OptimisticLockTest`](../src/test/java/com/ankurm/hibernatedemo/OptimisticLockTest.java).
|
||||
Entity: [`Book`](../src/main/java/com/ankurm/hibernatedemo/model/Book.java) — note the real
|
||||
`@Version` column and the `notes` LAZY collection, both load-bearing for the experiments below.
|
||||
|
||||
```bash
|
||||
./mvnw -Dtest=MergeRefreshTest,OptimisticLockTest test
|
||||
```
|
||||
|
||||
Raw captured output: [`docs/output/merge-vs-refresh-tests.txt`](output/merge-vs-refresh-tests.txt).
|
||||
(The `docs/output/merge-vs-refresh.txt` file, unchanged, is the older `CommandLineRunner`
|
||||
transcript behind the `mergerefresh` profile mentioned in the README — a different, narrower
|
||||
scenario than the three experiments below.)
|
||||
|
||||
## Contract vs observation
|
||||
|
||||
The textbook framing is "`merge()` pushes Java state to the database, `refresh()` pulls database
|
||||
state into Java — opposite directions of the same kind of operation." That's accurate as a
|
||||
description of data flow and useless as a guide to which one is dangerous. The three experiments
|
||||
below are about the part the contract doesn't specify: what each method does when the state it's
|
||||
holding is already stale, which is precisely the situation both exist to handle.
|
||||
|
||||
## Reframing: this is about entity state, not "data consistency"
|
||||
|
||||
`merge()` and `refresh()` don't care about your application's notion of consistency. They care
|
||||
about exactly one thing: what identity state (`@Version` value, or an unflushed field on a managed
|
||||
instance) the object handed to them holds at the moment they're called. Everything below follows
|
||||
from that, entity-state mechanics, not from anything data-consistency-flavored.
|
||||
|
||||
## Experiment 1 — merge() of a detached instance
|
||||
|
||||
**Config:** a `Book` row exists in the database. A session already holds its *own* managed
|
||||
instance of that row (via `get()`), before `merge()` is ever called on a separately-detached copy
|
||||
of the same row.
|
||||
|
||||
**Expected:** `merge()` returns some object representing the updated state.
|
||||
|
||||
**Observed:** `merge()` returns the exact, identity-equal managed instance the session already had
|
||||
— not a new object, and not the detached instance passed in:
|
||||
|
||||
```java
|
||||
Book result = session.merge(detached);
|
||||
assertThat(result).isSameAs(managed); // true
|
||||
assertThat(result).isNotSameAs(detached); // true
|
||||
```
|
||||
|
||||
This is the precise version of "`merge()` returns a managed copy" — it's not just *a* managed
|
||||
copy, it's *the* one instance this persistence context has already committed to tracking for this
|
||||
row, reused rather than replaced.
|
||||
|
||||
## Experiment 2 — optimistic-lock conflict: WHEN does it surface?
|
||||
|
||||
**Config:** a detached `Book` instance holds `version=0`. A second, independent session has since
|
||||
updated the same row and committed, advancing the database to `version=1`. The stale detached
|
||||
instance is then edited and merged.
|
||||
|
||||
**Expected (the common but imprecise claim):** "`merge()` throws `OptimisticLockException`."
|
||||
|
||||
**Observed, precisely:** it does — and specifically **at the `merge()` call itself**, not at
|
||||
`flush()` and not at `tx.commit()`:
|
||||
|
||||
```
|
||||
OptimisticLockException surfaced directly from the merge() call.
|
||||
exception: jakarta.persistence.OptimisticLockException: Row was already updated or deleted by
|
||||
another transaction for entity [com.ankurm.hibernatedemo.model.Book with id '4']
|
||||
```
|
||||
|
||||
The test doesn't assume this — it wraps `session.merge(detached)` in a `try/catch` first and only
|
||||
falls through to asserting the exception at `commit()` if `merge()` itself didn't throw, logging
|
||||
which path actually happened. On 7.4.1.Final, `merge()` re-selects the row as part of copying
|
||||
state and compares versions right there, before any flush is even scheduled — so the failure is as
|
||||
early as it can possibly be. This matters in code that wraps `merge()` calls expecting the
|
||||
exception only at commit time: on this version, it never gets that far.
|
||||
|
||||
## Experiment 3 — merge() with a LAZY collection under CascadeType.MERGE
|
||||
|
||||
**Config:** `Book.notes` is `FetchType.LAZY` and cascades `MERGE`. A `Book` is loaded and detached
|
||||
*without ever touching* `.getNotes()` — the collection proxy is confirmed uninitialized before
|
||||
detachment. The detached instance is edited and merged.
|
||||
|
||||
**Expected (the naive, plausible-sounding claim):** "an unfetched LAZY collection is never
|
||||
touched by `merge()`, since it was never loaded in the first place."
|
||||
|
||||
**Observed:** the opposite. `merge()` initializes the collection anyway:
|
||||
|
||||
```java
|
||||
Book merged = session.merge(detached);
|
||||
assertThat(Hibernate.isInitialized(merged.getNotes())).isTrue(); // true -- NOT false
|
||||
```
|
||||
|
||||
The reason is cascading itself: `CascadeType.MERGE` on `notes` means merging the parent requires
|
||||
merging each element of that collection too, and Hibernate cannot cascade to elements it hasn't
|
||||
loaded — so it loads them first. Remove `cascade = CascadeType.MERGE` from `Book.notes` and
|
||||
re-run this exact test and the result flips: the collection stays uninitialized, because nothing
|
||||
requires Hibernate to look at it. Cascading, not laziness, decides whether `merge()` touches an
|
||||
unfetched collection.
|
||||
|
||||
## Experiment 4 — refresh() silently discards an unflushed edit
|
||||
|
||||
**Config:** the `USER_EDIT` / `ADMIN_EDIT` scenario. A `Book.status` row starts at `USER_EDIT`. A
|
||||
separate admin process loads the row, sets `status=ADMIN_EDIT`, and commits. A second session then
|
||||
loads the row (now `ADMIN_EDIT` in the database), makes a local, unflushed edit back to
|
||||
`USER_EDIT`, and calls `session.refresh()` on the managed instance.
|
||||
|
||||
**Observed:**
|
||||
|
||||
```java
|
||||
managed.setStatus("USER_EDIT"); // local edit, never sent to the database
|
||||
session.refresh(managed);
|
||||
assertThat(managed.getStatus()).isEqualTo("ADMIN_EDIT"); // the local edit is gone
|
||||
```
|
||||
|
||||
No exception. No warning. `refresh()` re-runs the `SELECT` and overwrites every field on the
|
||||
managed instance with what the database currently holds — including the field holding the pending
|
||||
edit that was never flushed. The edit isn't rejected; it's erased.
|
||||
|
||||
## What surprised me building this
|
||||
|
||||
Going in, the plan was to demonstrate "`merge()` can silently overwrite concurrent changes" as
|
||||
the headline risk — that's the framing most write-ups use, and it's the one the article originally
|
||||
carried. Running Experiments 2 and 4 back to back showed the opposite. With a real `@Version`
|
||||
column in place, `merge()` is the one that refuses to write a stale change — loudly, at the
|
||||
earliest possible point. `refresh()` is the one that destroys data without a sound, and it does it
|
||||
to an edit that was never even sent to the database. The risk isn't "which method can overwrite
|
||||
the database" — both can, that's their job. It's "which one fails loudly when the state it's
|
||||
holding is stale," and on a versioned entity that's `refresh()`, not `merge()` — backwards from
|
||||
how the pairing is usually described. Strip the `@Version` column out and Experiment 2 flips: an
|
||||
unversioned `merge()` would apply the stale write without complaint. The column isn't incidental
|
||||
to the result; it's the entire reason the result comes out this way.
|
||||
|
||||
The LAZY-collection result (Experiment 3) was the other correction: the plan going in was to
|
||||
show that unfetched LAZY state is never touched by `merge()`. It is, specifically because of the
|
||||
cascade — a fact only visible by running the on/off comparison rather than asserting the more
|
||||
intuitive-sounding half of it.
|
||||
|
||||
## Decision tree
|
||||
|
||||
```
|
||||
Do you have a DETACHED instance you want written to the database?
|
||||
├─ Yes → merge()
|
||||
│ Does the entity carry @Version?
|
||||
│ ├─ Yes → a stale write throws OptimisticLockException AT THE merge() CALL — loud, safe
|
||||
│ └─ No → a stale write silently overwrites the current row — no different from update()
|
||||
│
|
||||
└─ No, you have a MANAGED instance and want it to reflect the current database row
|
||||
→ refresh()
|
||||
Does it have an unflushed local edit?
|
||||
├─ Yes → that edit is silently discarded, no exception — refresh() is NOT reversible
|
||||
└─ No → refresh() is a safe, ordinary re-read
|
||||
```
|
||||
|
||||
## Pessimistic locking, briefly
|
||||
|
||||
Pessimistic locking (`LockModeType.PESSIMISTIC_WRITE`, issuing `SELECT ... FOR UPDATE`) is the
|
||||
other tool for the same underlying problem — it prevents the conflict from ever existing rather
|
||||
than detecting it after the fact. Reach for it only when the retry cost of an
|
||||
`OptimisticLockException` is genuinely unacceptable (real-time seat/ticket reservation, high
|
||||
per-row contention); it holds a database lock for the duration of the transaction, which is the
|
||||
wrong tradeoff for the common case of a REST API with real user think-time between load and save.
|
||||
`@Version` optimistic locking is the sane default; this repo doesn't carry a dedicated scenario for
|
||||
pessimistic locking because there's no surprising runtime behavior to verify here beyond "the lock
|
||||
is held until commit," which the database's own documentation already states correctly.
|
||||
|
||||
[← Previous: 01 — get() vs getReference()](01-get-vs-load.md) | [Next: 03 — Inserting objects →](03-inserting-objects.md)
|
||||
Executable
+198
@@ -0,0 +1,198 @@
|
||||
# 03 — Hibernate 7 batch inserts: proving batching is working
|
||||
|
||||
[← Previous: 02 — merge() vs refresh()](02-merge-vs-refresh.md) | [Next: 04 — Annotations vs. XML mappings →](04-annotations-vs-xml.md)
|
||||
|
||||
Backs [ankurm.com: Hibernate 7 batch inserts](https://ankurm.com/mastering-hibernate-7-the-ultimate-guide-to-inserting-objects-efficiently/).
|
||||
|
||||
Test classes: [`IdentityBatchTest`](../src/test/java/com/ankurm/hibernatedemo/IdentityBatchTest.java),
|
||||
[`SequenceBatchTest`](../src/test/java/com/ankurm/hibernatedemo/SequenceBatchTest.java),
|
||||
[`AllocationSizeSweepTest`](../src/test/java/com/ankurm/hibernatedemo/AllocationSizeSweepTest.java),
|
||||
[`BatchSizeSweepTest`](../src/test/java/com/ankurm/hibernatedemo/BatchSizeSweepTest.java).
|
||||
|
||||
```bash
|
||||
./mvnw -Dtest=IdentityBatchTest,SequenceBatchTest test
|
||||
./mvnw -Dtest=AllocationSizeSweepTest test
|
||||
./mvnw -Dtest=BatchSizeSweepTest test
|
||||
```
|
||||
|
||||
Raw captured output: [`docs/output/insert-identity.txt`](output/insert-identity.txt),
|
||||
[`docs/output/insert-sequence.txt`](output/insert-sequence.txt),
|
||||
[`docs/output/allocation-and-batch-size-sweeps.txt`](output/allocation-and-batch-size-sweeps.txt).
|
||||
|
||||
## The discovery that opens this chapter: IDENTITY silently disables batching
|
||||
|
||||
Two entities, [`WidgetIdentity`](../src/main/java/com/ankurm/hibernatedemo/model/WidgetIdentity.java)
|
||||
and [`WidgetSequence`](../src/main/java/com/ankurm/hibernatedemo/model/WidgetSequence.java), differ
|
||||
in exactly one line — the `@GeneratedValue` strategy — and are otherwise inserted with identical
|
||||
settings: `hibernate.jdbc.batch_size=25`, `hibernate.order_inserts=true`. 30 rows each, same
|
||||
transaction shape, `hibernate.generate_statistics=true` reading the real counts.
|
||||
|
||||
## Results, up front
|
||||
|
||||
| | `entityInsertCount` | `prepareStatementCount` | Batching actually happening? |
|
||||
|---|---|---|---|
|
||||
| `WidgetIdentity` (`GenerationType.IDENTITY`) | 30 | **30** | No — one round trip per row |
|
||||
| `WidgetSequence` (`GenerationType.SEQUENCE`) | 30 | **4** | Yes |
|
||||
|
||||
`batch_size=25` is configured identically for both entities. It does nothing at all for
|
||||
`IDENTITY` — `prepareStatementCount` equals `entityInsertCount` exactly, meaning every insert is
|
||||
its own round trip. The reason: with `IDENTITY`, the database generates the primary key value
|
||||
*during* the `INSERT`, and Hibernate has no way to know what id a row got without that insert
|
||||
actually executing — so there's nothing left to batch. `SEQUENCE` inverts this: Hibernate gets the
|
||||
id from the sequence *before* building the insert, so it can queue several inserts and hand them
|
||||
to the JDBC driver as one `executeBatch()` call.
|
||||
|
||||
## Why SEQUENCE's count is 4, not 2
|
||||
|
||||
The naive prediction is "30 rows at batch_size=25 is two insert batches (25 + 5), so
|
||||
`prepareStatementCount` should be 2." Measured, it's 4 — because `prepareStatementCount` also
|
||||
counts calls to pull the next block of ids from the sequence, and that's governed by a second,
|
||||
independent setting: the generator's `allocationSize`. `WidgetSequence` sets `allocationSize=25`
|
||||
to match `batch_size`, so the first 25 ids come from one sequence call and the remaining 5 force a
|
||||
second — 2 insert batches + 2 sequence calls = 4. `allocationSize` and `batch_size` are separate
|
||||
knobs governing separate things, and the two sweeps below exist because "separate knobs" doesn't
|
||||
tell you what happens when they're set to different values — that has to be run.
|
||||
|
||||
## Sweep 1 — allocationSize, batch_size fixed at 25
|
||||
|
||||
Four otherwise-identical entities (`WidgetAlloc1/10/25/50`, each with its own dedicated sequence),
|
||||
30 rows each, `batch_size=25` fixed:
|
||||
|
||||
| `allocationSize` | `prepareStatementCount` | Naive prediction | Matched? |
|
||||
|---|---|---|---|
|
||||
| 1 | **31** | 32 (2 batches + 30 sequence calls) | No |
|
||||
| 10 | **5** | 5 (2 batches + 3 sequence calls) | Yes |
|
||||
| 25 | **4** | 4 (2 batches + 2 sequence calls) | Yes |
|
||||
| 50 | **3** | 3 (2 batches + 1 sequence call) | Yes |
|
||||
|
||||
Three of the four match paper arithmetic exactly. `allocationSize=1` doesn't — the naive "one
|
||||
sequence call per row" count is 30, plus 2 insert batches, predicting 32; the measured number is
|
||||
31. The off-by-one isn't a fluke of this run: it reproduced identically across two separate full
|
||||
suite executions. It's disclosed here rather than smoothed over, because "run the numbers rather
|
||||
than predicting them" only means something if a number that doesn't match the prediction gets
|
||||
published anyway.
|
||||
|
||||
## Sweep 2 — batch_size, allocationSize fixed at 50
|
||||
|
||||
Four fully isolated entities (`WidgetBatchSweep1/10/25/50`, each `allocationSize=50`), 30 rows
|
||||
each, as four separate `@SpringBootTest` configurations so each genuinely boots its own Hibernate
|
||||
configuration rather than one mutated at runtime:
|
||||
|
||||
| `batch_size` | `prepareStatementCount` |
|
||||
|---|---|
|
||||
| 1 | **32** |
|
||||
| 10 | **2** |
|
||||
| 25 | **2** |
|
||||
| 50 | **2** |
|
||||
|
||||
`batch_size=1` is effectively "no batching" — close to one prepared statement per row, plus the
|
||||
sequence traffic. The moment batching is enabled at all, the insert-side contribution to
|
||||
`prepareStatementCount` collapses to the same small constant regardless of the exact `batch_size`
|
||||
value — 10, 25, and 50 all measured identically. That does **not** mean `batch_size` stops
|
||||
mattering: it still governs how many rows go into each `executeBatch()` call at the JDBC driver
|
||||
level, which is real and documented — it just isn't a distinction this particular Hibernate
|
||||
statistic can see once batching is switched on at all. Reading `prepareStatementCount` answers
|
||||
"is batching happening," not "how big are the batches."
|
||||
|
||||
**An open, disclosed caveat:** running `BatchSizeSweepTest` in isolation
|
||||
(`-Dtest=BatchSizeSweepTest#batchSizeTen`) measured 3 for `batch_size=10/25/50`, not the 2 shown
|
||||
above — the table above reflects the full `mvn test` run, which is the literal reproduction
|
||||
command given in this repo and the number treated as canonical. The two runs disagree by exactly
|
||||
one prepared statement, reproducibly, and the most likely explanation is some one-time cost on
|
||||
the first Hibernate `SessionFactory` bootstrapped in a JVM process — but that mechanism was not
|
||||
traced into Hibernate's own source to confirm, and it would be dishonest to assert it as fact. Run
|
||||
both ways yourself; they're one flag apart.
|
||||
|
||||
## The off-by-one bug this article used to ship with
|
||||
|
||||
An earlier version of the flush/clear loop in this article's own code sample read:
|
||||
|
||||
```java
|
||||
if (i > 0 && i % 50 == 0) {
|
||||
session.flush();
|
||||
session.clear();
|
||||
}
|
||||
```
|
||||
|
||||
`i` is the 0-based loop index (`for (int i = 0; i < users.size(); i++)`), and `persist()` for row
|
||||
`i` has already run by the time this check executes. `i > 0 && i % 50 == 0` is true at
|
||||
`i = 50, 100, 150, ...` — but by the time `i` reaches 50, rows at index `0` through `50` have
|
||||
already been persisted, which is **51 rows**, not 50. Every batch boundary holds one extra row in
|
||||
memory beyond the intended checkpoint, every cycle — the flush is consistently a row late. The
|
||||
fix:
|
||||
|
||||
```java
|
||||
if ((i + 1) % 50 == 0) {
|
||||
session.flush();
|
||||
session.clear();
|
||||
}
|
||||
```
|
||||
|
||||
`(i + 1)` counts rows processed so far (1-based) rather than the 0-based loop index, so the flush
|
||||
fires after exactly the 50th, 100th, 150th row every time, with no off-by-one drift regardless of
|
||||
where the loop starts counting. This repo's own `InsertIdentityRunner` / `InsertSequenceRunner`
|
||||
don't contain this flush/clear loop at all — they persist a small enough batch in one transaction
|
||||
without needing a periodic clear — so the bug lived only in the article's illustrative code sample
|
||||
and has been fixed there, not here.
|
||||
|
||||
## Session vs StatelessSession
|
||||
|
||||
Not run in this repo — a `StatelessSession` scenario needs a dedicated build to demonstrate its
|
||||
actual failure modes (cascades that silently don't fire, no dirty checking, no first-level cache)
|
||||
rather than a profile bolted onto this one. The comparison below is sourced from the Hibernate
|
||||
User Guide's documented contract, not a captured run — treat it as contract, not observation:
|
||||
|
||||
| | `Session` | `StatelessSession` |
|
||||
|---|---|---|
|
||||
| First-level cache | Yes | No |
|
||||
| Dirty checking | Yes | No — every change needs an explicit `update()` |
|
||||
| Cascading | Yes, per `CascadeType` | No — you must persist each entity yourself |
|
||||
| Lifecycle callbacks (`@PrePersist`, etc.) | Yes | No |
|
||||
| Batching behavior | Governed by `hibernate.jdbc.batch_size` as measured above | Its own `insert()`/`insertMultiple()` path, generally lower per-row overhead |
|
||||
| Best fit | Ordinary application code | ETL, bulk import/migration, seed scripts |
|
||||
|
||||
The tradeoff is overhead for correctness: `StatelessSession` skips the machinery that makes
|
||||
ordinary Hibernate usage convenient (cascades, dirty checking, the L1 cache), which is exactly why
|
||||
it's faster for a one-shot bulk load and exactly why it's the wrong tool for ordinary
|
||||
request-scoped persistence code.
|
||||
|
||||
## Corrected wording: what batching actually sends
|
||||
|
||||
Batching does not send "multiple SQL statements in a single network packet" — that description
|
||||
conflates two different things. What actually happens: JDBC's `PreparedStatement.addBatch()` /
|
||||
`executeBatch()` groups several parameter sets for the *same* prepared statement and sends them in
|
||||
one client-to-server exchange, avoiding a full round-trip per row. Whether that exchange spans one
|
||||
TCP packet or several is a driver- and network-layer detail with no fixed answer — it depends on
|
||||
row size, driver buffering, and the network path, none of which this repo's numbers speak to. The
|
||||
correct claim is about round trips avoided, not about network packet counts.
|
||||
|
||||
## Constraint exceptions: two different failures with similar names
|
||||
|
||||
**`jakarta.validation.ConstraintViolationException`** (Bean Validation, `jakarta.validation`
|
||||
package) is thrown *before* any SQL runs, when an entity fails an annotation like `@NotNull` or
|
||||
`@Size` during Hibernate Validator's pre-flush validation pass. No database round trip happens at
|
||||
all in this case.
|
||||
|
||||
**`org.hibernate.exception.ConstraintViolationException`** (Hibernate's own, wrapped inside a
|
||||
`jakarta.persistence.PersistenceException`) is thrown *after* SQL runs and the database itself
|
||||
rejects the statement — a unique index, a foreign key, or a check constraint failing at the
|
||||
database level.
|
||||
|
||||
Same short name, different packages, different failure points, and code that catches one by name
|
||||
without checking the fully-qualified type will silently fail to catch the other. Catching
|
||||
`jakarta.persistence.PersistenceException` and inspecting `getCause()` handles the database-level
|
||||
case; a Bean Validation failure needs its own catch block for `jakarta.validation.ConstraintViolationException`
|
||||
before that.
|
||||
|
||||
## What surprised me building this
|
||||
|
||||
The identity-vs-sequence result itself wasn't the surprise — that IDENTITY disables batching is
|
||||
documented, if you know to look. The surprise was in the sweeps: `allocationSize=1` landing at 31
|
||||
instead of the paper-arithmetic 32, and the batch_size sweep collapsing to the same constant the
|
||||
moment batching is enabled at all regardless of the exact value, in a way that changes depending
|
||||
on whether the test runs alone or as part of the full suite. None of those three things would have
|
||||
made it into this article from reasoning about the configuration in the abstract — they only show
|
||||
up by actually running the sweep and being willing to publish a number that didn't match the
|
||||
prediction.
|
||||
|
||||
[← Previous: 02 — merge() vs refresh()](02-merge-vs-refresh.md) | [Next: 04 — Annotations vs. XML mappings →](04-annotations-vs-xml.md)
|
||||
Executable
+121
@@ -0,0 +1,121 @@
|
||||
# 04 — Annotations vs. XML mappings in Hibernate 7.4.5 — what actually still works
|
||||
|
||||
[← Previous: 03 — Inserting objects](03-inserting-objects.md) | [Next: 05 — JPA persistence annotations →](05-jpa-persistence-annotations.md)
|
||||
|
||||
Backs [ankurm.com: Hibernate 7 annotations vs. XML mappings](https://ankurm.com/hibernate-annotations-vs-xml-mappings-making-the-right-choice-in-hibernate-7/).
|
||||
|
||||
Post 4863 frames this as a two-way choice: annotations vs. `orm.xml`, with `hbm.xml` waved off
|
||||
as "deprecated." That framing undersells what actually happens when you boot Hibernate
|
||||
7.4.5.Final with each of these on the classpath, and it misses that there are really **three**
|
||||
XML dialects in play, not two. Everything below was booted, not read about — see
|
||||
[`docs/output/mappingstyle-xml-vs-annotations.txt`](output/mappingstyle-xml-vs-annotations.txt) for the verbatim run, and the test classes
|
||||
under [`src/test/java/com/ankurm/hibernatedemo/mappingstyle/`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/) for the exact setup of each case.
|
||||
|
||||
## `hbm.xml` is not dead — it is a live code path with a warning label
|
||||
|
||||
The Hibernate 6 story was: `hbm.xml` is deprecated, and `hibernate.transform_hbm_xml.enabled`
|
||||
is a shim that rewrites it into the modern model at boot. That shim setting still exists in
|
||||
7.4.5 (`org.hibernate.cfg.MappingSettings.TRANSFORM_HBM_XML`, and the whole
|
||||
`org.hibernate.boot.jaxb.hbm.*` package plus an `HbmXmlTransformer` are present in
|
||||
`hibernate-core-7.4.5.Final.jar`), but it is **not required** to use `hbm.xml`.
|
||||
|
||||
[`HbmXmlBootTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/HbmXmlBootTest.java) and [`HbmXmlRuntimeTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/HbmXmlRuntimeTest.java) put a real, annotation-free POJO
|
||||
([`HbmEmployee`](../src/main/java/com/ankurm/hibernatedemo/mappingstyle/HbmEmployee.java)) on the classpath with only an [`.hbm.xml` mapping](../src/test/resources/com/ankurm/hibernatedemo/mappingstyle/HbmEmployee.hbm.xml), and boot a plain Hibernate
|
||||
`SessionFactory` three ways:
|
||||
|
||||
- default settings (no `transform_hbm_xml.enabled` at all) — **boots successfully**, logs one
|
||||
WARN: `HHH90000028: Support for <hibernate-mappings/> is deprecated ... migrate to orm.xml or
|
||||
mapping.xml, or enable hibernate.transform_hbm_xml.enabled for on the fly transformation`
|
||||
- `hibernate.transform_hbm_xml.enabled=true` — boots successfully, no observable behavior
|
||||
difference for a simple mapping
|
||||
- `hibernate.transform_hbm_xml.enabled=false` (explicit) — **also boots successfully**
|
||||
|
||||
`HbmXmlRuntimeTest` goes further: it actually persists and loads an `HbmEmployee` row through
|
||||
the hbm.xml-only mapping, with the transform setting deliberately unset, and it round-trips
|
||||
correctly. So the honest 7.4.5 status of `hbm.xml` is: **it still fully works, unmodified,
|
||||
with a WARN-level deprecation notice** — not a shim you must opt into, not a hard failure, and
|
||||
not silently broken. The "transform" setting appears to matter for hbm.xml features that no
|
||||
longer have a native binding path in 7.x and must be rewritten into the modern model to be
|
||||
understood at all; a plain `<class>`/`<id>`/`<property>` mapping like this one never needs it.
|
||||
Treat any blog claim that `hbm.xml` "requires" the transform flag, or throws without it, as
|
||||
wrong for 7.4.5 — it is a live code path. (Chapter 14 hits the same "orm.xml still works with
|
||||
zero registration effort" theme from the named-query angle — see
|
||||
[`14 — Named queries`](14-named-queries.md#named-queries-in-ormxml).)
|
||||
|
||||
## `orm.xml` really can define an entire entity, annotation-free
|
||||
|
||||
Post 4863's `orm.xml` example only *overrides* an already-annotated `Employee`. It never proves
|
||||
`orm.xml` can carry a mapping on its own. [`OrmXmlMappingResourcesTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/OrmXmlMappingResourcesTest.java) does: [`OrmXmlOnlyEntity`](../src/main/java/com/ankurm/hibernatedemo/mappingstyle/OrmXmlOnlyEntity.java)
|
||||
carries **zero** JPA/Hibernate annotations — not even `@Entity` — and its entire mapping lives
|
||||
in [`orm-xml-only-mapping.xml`](../src/test/resources/orm-xml-only-mapping.xml). The Spring Boot wiring that makes this work is
|
||||
`spring.jpa.mapping-resources` (confirmed via `javap` on
|
||||
`org.springframework.boot.jpa.autoconfigure.JpaProperties` in `spring-boot-jpa-4.1.1.jar` —
|
||||
note the package: Boot 4's autoconfigure split moved this off the old
|
||||
`org.springframework.boot.autoconfigure.orm.jpa` path entirely). With that one property set,
|
||||
Hibernate creates `xml_only_widgets`, and a JPQL query (`select o from OrmXmlOnlyEntity o ...`)
|
||||
against it succeeds — the entity name resolves purely from the XML.
|
||||
|
||||
## XML wins on conflict — confirmed, not just documented
|
||||
|
||||
Post 4863's Q5 claims "XML always wins over annotations." [`AnnotationXmlOverrideTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/AnnotationXmlOverrideTest.java) proves it
|
||||
mechanically: [`OverrideEntity`](../src/main/java/com/ankurm/hibernatedemo/mappingstyle/OverrideEntity.java)`.value` is annotated `@Column(name = "annotation_name")`, and a
|
||||
matching [`orm-xml-override-mapping.xml`](../src/test/resources/orm-xml-override-mapping.xml) entry maps the same field to `xml_name`. Reading the runtime metamodel
|
||||
(`SessionFactoryImplementor.getMappingMetamodel().getEntityDescriptor(...).getPropertyColumnNames(...)`)
|
||||
confirms the live column name is `xml_name`, and a native query against that literal column
|
||||
name returns the persisted value. The article's claim is correct.
|
||||
|
||||
## `<xml-mapping-metadata-complete/>` is not an override switch — it is an annotation kill switch
|
||||
|
||||
This is the sharpest correction. The natural assumption is that
|
||||
`<persistence-unit-metadata><xml-mapping-metadata-complete/></persistence-unit-metadata>` means
|
||||
"XML overrides annotations for the attributes XML mentions." [`XmlMappingMetadataCompleteTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/XmlMappingMetadataCompleteTest.java)
|
||||
shows it is stronger than that: with [metadata-complete set](../src/test/resources/orm-xml-metadata-complete.xml), `OverrideEntity`'s `@Id
|
||||
@GeneratedValue` on the `id` field is **entirely ignored**, even though the matching `orm.xml`
|
||||
entry never mentions `id` at all. Boot fails with
|
||||
`org.hibernate.AnnotationException: Entity '...OverrideEntity' has no identifier`. Metadata-complete
|
||||
does not selectively override — it switches off annotation processing for the whole persistence
|
||||
unit, and any attribute XML doesn't repeat is simply gone.
|
||||
|
||||
## The real "what XML can do that annotations can't" — a third XML dialect
|
||||
|
||||
Post 4863 never mentions this, and it changes the shape of the whole topic: Hibernate 7 ships a
|
||||
**third** XML mapping format, distinct from both legacy `hbm.xml` and JPA-standard `orm.xml`.
|
||||
It lives in `org/hibernate/xsd/mapping/mapping-7.0.xsd` inside `hibernate-core-7.4.5.Final.jar`,
|
||||
under namespace `http://www.hibernate.org/xsd/orm/mapping`, and its own XSD documentation calls
|
||||
it out explicitly: *"XSD which 'extends' the JPA orm.xml XSD adding support for Hibernate
|
||||
specific features."* This is exactly the second migration target the `HHH90000028` deprecation
|
||||
warning names ("migrate to orm.xml **or mapping.xml**").
|
||||
|
||||
The difference is not cosmetic. Grepping both schemas for Hibernate-only concepts:
|
||||
|
||||
| Element | `orm_3_2.xsd` (JPA-standard `orm.xml`) | `mapping-7.0.xsd` (Hibernate's native dialect) |
|
||||
|---|---|---|
|
||||
| `<natural-id>` | absent | present |
|
||||
| `<formula>` / `<discriminator-formula>` / `<join-formula>` | absent | present |
|
||||
| `<filter>`-related elements | absent | present (11 occurrences) |
|
||||
|
||||
[`MappingXmlNaturalIdTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/MappingXmlNaturalIdTest.java) proves this is not just schema noise: [`MappingXmlNaturalIdEntity`](../src/main/java/com/ankurm/hibernatedemo/mappingstyle/MappingXmlNaturalIdEntity.java) has
|
||||
**zero** annotations, its `<natural-id>` is declared purely in [`mapping-xml-natural-id.xml`](../src/test/resources/mapping-xml-natural-id.xml)
|
||||
(root element `<entity-mappings xmlns="http://www.hibernate.org/xsd/orm/mapping" version="7.0">`),
|
||||
and `session.byNaturalId(...).using("sku", ...).load()` resolves it correctly. So the accurate
|
||||
answer to "what can XML express that annotations can't" is actually inverted from how the
|
||||
article poses it: the JPA-portable `orm.xml` dialect can express **less** than annotations
|
||||
(no Hibernate extensions at all), while Hibernate's own `mapping.xml` dialect can express
|
||||
**anything annotations can**, including natural ids, formulas, and filters — you trade JPA
|
||||
portability for that power, not gain something unavailable to annotations. (Chapter 06 covers
|
||||
`@NaturalId` from the annotation side; this is the same feature expressed purely in XML.)
|
||||
|
||||
## Practical takeaway
|
||||
|
||||
- Legacy `hbm.xml`: still boots and runs in 7.4.5, WARN-level deprecated, no forced migration.
|
||||
- `orm.xml` (JPA-standard): fully capable of defining an entity from scratch; wired into Spring
|
||||
Boot via `spring.jpa.mapping-resources`; portable across providers but capped at what
|
||||
`orm_3_2.xsd` can express — no Hibernate-only concepts.
|
||||
- Hibernate's native `mapping.xml` (`mapping-7.0.xsd`): the actual annotation-equivalent XML
|
||||
dialect, including `@NaturalId`, `@Formula`, and filters — not portable to other JPA
|
||||
providers, but not missing anything either.
|
||||
- XML (either dialect) always wins over a conflicting annotation for the same attribute.
|
||||
- `xml-mapping-metadata-complete` disables annotation processing for the *entire* persistence
|
||||
unit, not just the attributes the XML repeats — a much bigger blast radius than "override."
|
||||
|
||||
[← Previous: 03 — Inserting objects](03-inserting-objects.md) | [Next: 05 — JPA persistence annotations →](05-jpa-persistence-annotations.md)
|
||||
Executable
+139
@@ -0,0 +1,139 @@
|
||||
# 05 — JPA persistence annotations in Hibernate 7.4.5 / Jakarta Persistence 3.2 — what's actually new or broken
|
||||
|
||||
[← Previous: 04 — Annotations vs. XML mappings](04-annotations-vs-xml.md) | [Next: 06 — Natural IDs →](06-natural-ids.md)
|
||||
|
||||
Backs [ankurm.com: mastering JPA persistence annotations in Hibernate 7](https://ankurm.com/mastering-hibernate-7-the-ultimate-guide-to-jpa-persistence-annotations/).
|
||||
|
||||
Post 4864 is a solid annotation catalogue; this chapter deliberately does not repeat it. Instead
|
||||
it covers what is wrong, deprecated, or new in 3.2 that the article predates or gets slightly
|
||||
wrong, each verified by `javap` on the real jars and a runnable test — see
|
||||
[`docs/output/persistenceannotations-tests.txt`](output/persistenceannotations-tests.txt) and
|
||||
[`src/test/java/com/ankurm/hibernatedemo/persistenceannotations/`](../src/test/java/com/ankurm/hibernatedemo/persistenceannotations/).
|
||||
|
||||
## `@Temporal` is formally `@Deprecated(since = "3.2")` — and it is a silent no-op, not silent-silent
|
||||
|
||||
`javap -v` on `jakarta.persistence.Temporal` in `jakarta.persistence-api-3.2.0.jar` shows:
|
||||
|
||||
```
|
||||
RuntimeVisibleAnnotations:
|
||||
java.lang.Deprecated(since="3.2")
|
||||
```
|
||||
|
||||
Post 4864 says (correctly) that `@Temporal` isn't needed for `java.time` types. What it doesn't
|
||||
say: putting `@Temporal` on a `java.time.LocalDate` field anyway does **not** boot silently.
|
||||
[`TemporalOnJavaTimeTest`](../src/test/java/com/ankurm/hibernatedemo/persistenceannotations/TemporalOnJavaTimeTest.java) shows Hibernate logs a WARN at boot for every such field, using [`TemporalOnLocalDateEntity`](../src/main/java/com/ankurm/hibernatedemo/persistenceannotations/TemporalOnLocalDateEntity.java):
|
||||
|
||||
```
|
||||
HHH90000033: Encountered use of deprecated annotation [interface jakarta.persistence.Temporal]
|
||||
at ...TemporalOnLocalDateEntity.eventDate.
|
||||
```
|
||||
|
||||
The mapping itself is unaffected — the field round-trips identically with or without the
|
||||
annotation — but "silent" is the wrong word for what happens; it is a one-line-per-field boot
|
||||
warning, which is worth knowing if you're trying to track down noisy startup logs after a
|
||||
Hibernate upgrade. (Chapter 13 measures the same deprecation warning against an `Instant` field
|
||||
and covers the rest of `@Temporal`'s replacement, `@TimeZoneStorage` — see
|
||||
[`13 — Date and time mapping`](13-date-and-time-mapping.md#temporal-verified-deprecated-and-verified-harmless-when-misapplied).)
|
||||
|
||||
## `@Enumerated` default (ORDINAL): the real failure mode, reproduced
|
||||
|
||||
The article correctly recommends `EnumType.STRING` over the ORDINAL default, but doesn't show
|
||||
the failure concretely. [`EnumOrdinalDefaultTest`](../src/test/java/com/ankurm/hibernatedemo/persistenceannotations/EnumOrdinalDefaultTest.java) does: persist a row with `OrderStatus.SHIPPED`
|
||||
(ordinal 1 in the original 3-constant enum, [`EnumDefaultOrdinalEntity`](../src/main/java/com/ankurm/hibernatedemo/persistenceannotations/EnumDefaultOrdinalEntity.java)), then read the **same physical row** back through a
|
||||
second entity/enum pair ([`EnumReorderedV2Entity`](../src/main/java/com/ankurm/hibernatedemo/persistenceannotations/EnumReorderedV2Entity.java)) where a new constant (`PENDING_REVIEW`) was inserted *before* `SHIPPED`.
|
||||
No exception anywhere — the row silently comes back tagged `PENDING_REVIEW`. This is exactly the
|
||||
"someone edited the enum without a migration" scenario, reproduced with two real
|
||||
`SessionFactory` instances against the same physical H2 database (needed because Hibernate
|
||||
refuses to map the same table twice inside one persistence unit, so this can't be done inside a
|
||||
single Spring context).
|
||||
|
||||
## `@JdbcTypeCode(SqlTypes.JSON)` works on H2 2.4.240 — but only with a JSON mapper on the classpath
|
||||
|
||||
The article recommends `@JdbcTypeCode(SqlTypes.JSON)` without dependency caveats. First attempt
|
||||
against the existing `hibernate-demo` pom (Boot starter + Data JPA + H2, no Jackson) failed
|
||||
outright, tested against [`JsonColumnEntity`](../src/main/java/com/ankurm/hibernatedemo/persistenceannotations/JsonColumnEntity.java) in [`JsonColumnOnH2Test`](../src/test/java/com/ankurm/hibernatedemo/persistenceannotations/JsonColumnOnH2Test.java):
|
||||
|
||||
```
|
||||
org.hibernate.HibernateException: Could not find a FormatMapper for the JSON format, which is
|
||||
required for mapping JSON types. JSON FormatMapper configuration is automatic, but requires that
|
||||
you have either Jackson or a JSONB implementation like Yasson on the class path.
|
||||
```
|
||||
|
||||
This matters because `spring-boot-starter-data-jpa` does **not** pull in Jackson — most real
|
||||
apps have Jackson anyway (via `spring-boot-starter-web`), which is presumably why this is easy
|
||||
to miss. Adding Jackson 3 makes it work cleanly, H2 storing it as a native `JSON` column type:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>tools.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>3.1.5</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
(Note the groupId: Boot 4.1.1's BOM calls this artifact `tools.jackson:jackson-bom` at the BOM
|
||||
level, but the actual `jackson-databind` module publishes under `tools.jackson.core`, not
|
||||
`tools.jackson` — the deploy step will fail with a bare `groupId:jackson-databind` guess.)
|
||||
Hibernate ships `Jackson3JsonFormatMapper` and the older `JacksonJsonFormatMapper` (Jackson 2)
|
||||
side by side in 7.4.5, so either major version works once present.
|
||||
|
||||
## The equals/hashCode HashSet trap — reproduced end to end
|
||||
|
||||
Post 4864's Q5 warns against surrogate-id-based `equals()`/`hashCode()`. [`IdBasedEqualsHashSetTrapTest`](../src/test/java/com/ankurm/hibernatedemo/persistenceannotations/IdBasedEqualsHashSetTrapTest.java)
|
||||
builds the actual failure: an entity ([`IdBasedEqualsEntity`](../src/main/java/com/ankurm/hibernatedemo/persistenceannotations/IdBasedEqualsEntity.java) / [`IdentityHashSetEntity`](../src/main/java/com/ankurm/hibernatedemo/persistenceannotations/IdentityHashSetEntity.java)) with `equals()`/`hashCode()` on the `@GeneratedValue` `id`
|
||||
is added to a `HashSet` while `id` is still `null`, then `persist()`d. The **same reference**,
|
||||
looked up in the **same** `Set`, comes back `contains() == false` — because the hash code
|
||||
changed after insertion and `HashSet` is now probing the wrong bucket. Manual iteration with
|
||||
`equals()` still finds it, confirming it's specifically the hash-bucket indexing that breaks,
|
||||
not equality itself. (Chapter 06 shows the natural-id-based version of `equals()`/`hashCode()`
|
||||
does not have this problem — see
|
||||
[`06 — Natural IDs`](06-natural-ids.md#the-equalshashcode-advice-holds-up--with-one-nuance-the-article-doesnt-mention).)
|
||||
|
||||
## Access type mixing: two real, non-obvious symptoms
|
||||
|
||||
The article never discusses `@Access`/mixed access at all. [`MixedAccessTest`](../src/test/java/com/ankurm/hibernatedemo/persistenceannotations/MixedAccessTest.java) (against [`MixedAccessEntity`](../src/main/java/com/ankurm/hibernatedemo/persistenceannotations/MixedAccessEntity.java)) reproduces two
|
||||
things worth knowing:
|
||||
|
||||
1. Hibernate's default PROPERTY-access strategy **requires a setter**, even for a logically
|
||||
read-only derived attribute — omitting one throws `PropertyNotFoundException: Could not locate
|
||||
setter method for property 'computedLabel'` at boot. A no-op setter is the workaround if the
|
||||
attribute is truly meant to be read-only.
|
||||
2. A PROPERTY-access getter with side effects (a call counter, here) is invoked **more than
|
||||
once per flush** by Hibernate (2 calls observed for one insert) — once for dirty-check
|
||||
comparison, once for the actual write. Any "just compute it in the getter" derived
|
||||
PROPERTY-access attribute pays that cost on every flush, not once per logical read.
|
||||
|
||||
## What's actually new in Jakarta Persistence 3.2 (verified via `javap` on `jakarta.persistence-api-3.2.0.jar`)
|
||||
|
||||
Three things this article predates, each confirmed present in the 3.2.0 jar and exercised in
|
||||
[`Jpa32NewFeaturesTest`](../src/test/java/com/ankurm/hibernatedemo/persistenceannotations/Jpa32NewFeaturesTest.java):
|
||||
|
||||
- **`@EnumeratedValue`** (`@Target(FIELD)` only — cannot go on a getter) lets an enum control its
|
||||
own persisted representation via a designated field. Tested against [`EnumeratedValueEntity`](../src/main/java/com/ankurm/hibernatedemo/persistenceannotations/EnumeratedValueEntity.java): a `Priority` enum with a `code`
|
||||
field (`"L"`/`"M"`/`"H"`) persists that exact string, not the ordinal or `name()` — but it
|
||||
still needs `@Enumerated(EnumType.STRING)` on the entity field, or boot fails with
|
||||
`@EnumeratedValue for EnumType.ORDINAL must be placed on a field whose type is byte, short, or
|
||||
int` (ORDINAL is still JPA's overall default even when `@EnumeratedValue` is present).
|
||||
- **`TypedQuery.getSingleResultOrNull()`** returns `null` for a zero-row match instead of
|
||||
throwing `NoResultException` — confirmed via `javap` on `jakarta.persistence.TypedQuery` and
|
||||
exercised directly. (Chapter 14 exercises the same method on a plain `Query` — see
|
||||
[`14 — Named queries`](14-named-queries.md#getsingleresultornull-vs-getsingleresult).)
|
||||
- **JPQL constructor expressions targeting a Java `record`** work: `select new
|
||||
com.example.PriorityCountView(e.priority, count(e)) from ... group by e.priority` populates a
|
||||
`record` [`PriorityCountView(Priority priority, long total)`](../src/main/java/com/ankurm/hibernatedemo/persistenceannotations/PriorityCountView.java) via its canonical constructor,
|
||||
matched positionally, exactly like a regular DTO class would have been pre-3.2.
|
||||
|
||||
## Numbers
|
||||
|
||||
| Test | Result | Source |
|
||||
|---|---|---|
|
||||
| `@Temporal` on `LocalDate` | boots + round-trips; 1 WARN log line per field | `persistenceannotations-tests.txt` |
|
||||
| Enum ORDINAL reorder | stored ordinal 1 resolves to wrong constant, no exception | `persistenceannotations-tests.txt` |
|
||||
| `@JdbcTypeCode(JSON)` on H2 | works once `tools.jackson.core:jackson-databind` present; H2 column type = `JSON` | `persistenceannotations-tests.txt` |
|
||||
| Surrogate-id equals in HashSet | `contains()` false after persist, same reference | `persistenceannotations-tests.txt` |
|
||||
| Mixed access getter | called 2x per flush | `persistenceannotations-tests.txt` |
|
||||
| `@EnumeratedValue` | persists `"H"` not ordinal `2` or name `"HIGH"` | `persistenceannotations-tests.txt` |
|
||||
|
||||
The exact failure, reproduced with every JSON provider stripped off the classpath, is captured in [`docs/output/persistenceannotations-json-no-formatmapper.txt`](output/persistenceannotations-json-no-formatmapper.txt) — `spring-boot-starter-data-jpa` alone does not bring one.
|
||||
|
||||
[← Previous: 04 — Annotations vs. XML mappings](04-annotations-vs-xml.md) | [Next: 06 — Natural IDs →](06-natural-ids.md)
|
||||
Executable
+182
@@ -0,0 +1,182 @@
|
||||
# 06 — Hibernate 7 Natural IDs — what L1 and L2 actually give you, measured
|
||||
|
||||
[← Previous: 05 — JPA persistence annotations](05-jpa-persistence-annotations.md) | [Next: 07 — Immutable entities →](07-immutable-entities.md)
|
||||
|
||||
Backs [ankurm.com: Hibernate 7 natural IDs](https://ankurm.com/master-hibernate-7-natural-ids-the-definitive-guide-for-high-performance-java-apps/).
|
||||
|
||||
Post 4865 makes several precise claims about what natural-id resolution buys you with and
|
||||
without a second-level cache. All of them were tested with Hibernate Statistics rather than
|
||||
taken on faith — see [`docs/output/naturalid-tests.txt`](output/naturalid-tests.txt) for the verbatim counts and the test
|
||||
classes under [`src/test/java/com/ankurm/hibernatedemo/naturalid/`](../src/test/java/com/ankurm/hibernatedemo/naturalid/) for exact setup.
|
||||
|
||||
## The API surface: three methods, not two
|
||||
|
||||
`javap` on `org.hibernate.Session` in `hibernate-core-7.4.5.Final.jar` confirms all three natural-id
|
||||
entry points exist, each with `Class` and entity-name (`String`) overloads:
|
||||
|
||||
```
|
||||
NaturalIdLoadAccess<T> byNaturalId(Class<T>)
|
||||
SimpleNaturalIdLoadAccess<T> bySimpleNaturalId(Class<T>)
|
||||
NaturalIdMultiLoadAccess<T> byMultipleNaturalId(Class<T>)
|
||||
```
|
||||
|
||||
Post 4865 only ever demonstrates `byNaturalId(...).using(...).load()` and
|
||||
`byMultipleNaturalId(...).multiLoad(...)`. It never mentions `bySimpleNaturalId`, which is the
|
||||
more ergonomic form for the single-field case the article's own `Product`/`sku` example uses —
|
||||
`session.bySimpleNaturalId(Product.class).load("SKU-123")` instead of
|
||||
`.byNaturalId(Product.class).using("sku", "SKU-123").load()`. Not wrong, just an incomplete API
|
||||
tour; [`NaturalIdL1CacheTest`](../src/test/java/com/ankurm/hibernatedemo/naturalid/NaturalIdL1CacheTest.java) and [`NaturalIdL2CacheTest`](../src/test/java/com/ankurm/hibernatedemo/naturalid/NaturalIdL2CacheTest.java) use `bySimpleNaturalId` throughout to
|
||||
close that gap, exercising [`NaturalIdProduct`](../src/main/java/com/ankurm/hibernatedemo/naturalid/NaturalIdProduct.java) and [`CachedNaturalIdProduct`](../src/main/java/com/ankurm/hibernatedemo/naturalid/CachedNaturalIdProduct.java) respectively.
|
||||
|
||||
## The central question: does L1 save a query, with NO L2 cache configured?
|
||||
|
||||
**Yes — confirmed exactly as the article claims.** `NaturalIdL1CacheTest` persists a row, then
|
||||
calls `session.bySimpleNaturalId(NaturalIdProduct.class).load("SKU-L1-1")` twice in the *same*
|
||||
session, with no `@NaturalIdCache`, no `@Cache`, no L2 provider configured anywhere:
|
||||
|
||||
- 1st call: 1 query (`getPrepareStatementCount()` goes from 0 to 1)
|
||||
- 2nd call, same session: **still 1** — zero additional queries, and the returned reference is
|
||||
`isSameAs()` the first
|
||||
|
||||
A second test in the same class proves the flip side the article also asserts: a **new**
|
||||
session repeating the identical lookup *does* re-fire the query (cumulative count goes from 1 to
|
||||
2). So the L1 natural-id-to-PK map is real, it does save a query on repeat lookups, and it dies
|
||||
with the session exactly as documented.
|
||||
|
||||
## Turning on L2: `hibernate-jcache` + `ehcache`
|
||||
|
||||
The article recommends "@NaturalIdCache is mandatory for cross-session performance" without
|
||||
showing numbers. To get real ones, this required going online (these two dependencies were not
|
||||
already warm in the sandbox's `~/.m2`):
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.hibernate.orm</groupId>
|
||||
<artifactId>hibernate-jcache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>3.10.8</version>
|
||||
<classifier>jakarta</classifier>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
Two things worth flagging for anyone reproducing this: (1) `hibernate-jcache` correctly pulls
|
||||
`javax.cache:cache-api` — **not** a `jakarta.cache` artifact, because JSR-107 (JCache) was never
|
||||
migrated to the Jakarta namespace, unlike JPA/Bean Validation/etc.; (2) plain `org.ehcache:ehcache`
|
||||
resolves but drags in an ancient `javax.xml.bind:jaxb-api` transitively through
|
||||
`jaxb-runtime` that fails to resolve from Maven Central (a dead `maven.java.net` mirror) — the
|
||||
`jakarta` classifier plus excluding `jaxb-runtime` sidesteps it cleanly.
|
||||
|
||||
Settings used (`hibernate.cache.region.factory_class=jcache`,
|
||||
`hibernate.javax.cache.provider=org.ehcache.jsr107.EhcacheCachingProvider`) are exercised in
|
||||
`NaturalIdL2CacheTest`, booted as a standalone `SessionFactory` (not through the shared Spring
|
||||
context) so the L2 configuration doesn't leak into the other agents' tests. **This is the same
|
||||
`hibernate-jcache` dependency that turns out to have a much bigger, repo-wide side effect than
|
||||
"enables the natural-id cache when you ask for it" — see
|
||||
[chapter 09's writeup of `JCacheOnClasspathAutoEnablesL2Test`](09-testing-in-memory-databases.md#hibernate-jcache-on-the-classpath-turns-on-l2-for-everyone-whether-you-asked-or-not)
|
||||
for why `application.yml` in this repo pins `hibernate.cache.use_second_level_cache: false`
|
||||
explicitly, everywhere, regardless of what any individual chapter wants.**
|
||||
|
||||
## The surprise: `@NaturalIdCache` populates on INSERT, not on first lookup
|
||||
|
||||
The natural mental model is "L2 cache fills on the first miss." That is only half true.
|
||||
`bySimpleNaturalId_withNaturalIdCache_crossSession_savesTheQuery` shows that immediately after
|
||||
`persist()` + `commit()` on a `@NaturalIdCache`-annotated entity, `Statistics.getNaturalIdCachePutCount()`
|
||||
is already `1` — **before anyone has looked the entity up by its natural id at all.** The
|
||||
consequence: both a same-process "first" lookup and a genuinely new-session lookup resolve with
|
||||
**zero** additional queries and register as cache hits (`getNaturalIdCacheHitCount()` = 2 across
|
||||
both). If your mental model of L2 warm-up is "miss once per cold value," that is wrong for
|
||||
entities inserted through Hibernate itself.
|
||||
|
||||
To see the miss-then-hit path the article's mental model actually describes,
|
||||
`bySimpleNaturalId_rowInsertedOutsideHibernate_firstLookupIsARealMiss_secondIsARealHit` inserts a
|
||||
row via raw JDBC (bypassing Hibernate's persist-time cache population entirely). *That* row
|
||||
produces a real recorded miss + put on the first `bySimpleNaturalId` call (1 query, 1 miss,
|
||||
1 put), and a real hit with zero additional queries on the second, brand-new-session call. Both
|
||||
behaviors are real; the article only describes the second one, and most natural-id rows in a
|
||||
typical app are inserted through Hibernate, which means the first (surprising) path is actually
|
||||
the common case in practice, not the edge case.
|
||||
|
||||
## Mutability: immutable natural ids are enforced, not just conventionally recommended
|
||||
|
||||
Post 4865 recommends immutability as a best practice but doesn't say what enforcement exists.
|
||||
[`NaturalIdMutabilityTest`](../src/test/java/com/ankurm/hibernatedemo/naturalid/NaturalIdMutabilityTest.java) shows Hibernate actively checks it: mutating a
|
||||
`@NaturalId` field left at its default (`mutable = false`, [`ImmutableNaturalIdEntity`](../src/main/java/com/ankurm/hibernatedemo/naturalid/ImmutableNaturalIdEntity.java)) and flushing throws
|
||||
|
||||
```
|
||||
org.hibernate.HibernateException: An immutable natural identifier of entity
|
||||
...ImmutableNaturalIdEntity was altered from `CODE-A` to `CODE-B`
|
||||
```
|
||||
|
||||
This fires even with no `@Column(updatable = false)` guard on the column — it is Hibernate's own
|
||||
natural-id consistency check, not a side effect of a JPA column setting. `@NaturalId(mutable =
|
||||
true)` ([`MutableNaturalIdEntity`](../src/main/java/com/ankurm/hibernatedemo/naturalid/MutableNaturalIdEntity.java)), by contrast, flushes the change through cleanly (verified via a native query reading the
|
||||
updated column back), and a subsequent `bySimpleNaturalId` lookup by the *old* value correctly
|
||||
returns `null` while the *new* value resolves to the same row — no stale L1 entry survives the
|
||||
mutation within the same test's fresh sessions.
|
||||
|
||||
## Composite natural ids: the article's exact code sample, verified
|
||||
|
||||
[`Department`](../src/main/java/com/ankurm/hibernatedemo/naturalid/Department.java)'s two-field `@NaturalId` (`company`, `deptCode`) is lifted straight from post
|
||||
4865's example. [`CompositeNaturalIdTest`](../src/test/java/com/ankurm/hibernatedemo/naturalid/CompositeNaturalIdTest.java) proves it actually works: two [`Department`](../src/main/java/com/ankurm/hibernatedemo/naturalid/Department.java) rows with the
|
||||
*same* `deptCode` ("ENG-01") at two *different* [`Company`](../src/main/java/com/ankurm/hibernatedemo/naturalid/Company.java) instances resolve independently via
|
||||
`session.byNaturalId(Department.class).using("company", acme).using("deptCode", "ENG-01").load()`,
|
||||
in exactly one query. The generated SQL, captured verbatim:
|
||||
|
||||
```sql
|
||||
select d1_0.id,c1_0.id,c1_0.name,d1_0.dept_code,d1_0.name
|
||||
from department d1_0
|
||||
left join company c1_0 on c1_0.id=d1_0.company_id
|
||||
where d1_0.company_id=? and d1_0.dept_code=?
|
||||
```
|
||||
|
||||
Note it filters on `company_id` (the FK column), not by joining into `Company`'s own natural id
|
||||
or PK independently — the composite key is resolved as a single WHERE clause, as expected.
|
||||
|
||||
## The equals/hashCode advice holds up — with one nuance the article doesn't mention
|
||||
|
||||
Posts 4864/4865 recommend basing `equals()`/`hashCode()` on the natural id rather than the
|
||||
surrogate id, specifically to avoid the "hash code changes after `persist()`" trap. This was
|
||||
tested head-to-head against the surrogate-id version (see the sibling `persistenceannotations`
|
||||
package's [`IdBasedEqualsHashSetTrapTest`](../src/test/java/com/ankurm/hibernatedemo/persistenceannotations/IdBasedEqualsHashSetTrapTest.java), which reproduces the surrogate-id failure — see
|
||||
[chapter 05](05-jpa-persistence-annotations.md#the-equalshashcode-hashset-trap--reproduced-end-to-end)):
|
||||
with natural-id-based `equals()`/`hashCode()` ([`NaturalIdEqualsEntity`](../src/main/java/com/ankurm/hibernatedemo/naturalid/NaturalIdEqualsEntity.java)), an entity added to a `HashSet` *before* `persist()`
|
||||
is still found by `contains()` *after* `persist()` — the advice is correct, because the natural
|
||||
id (and hence the hash code) is set at construction time and never changes.
|
||||
|
||||
The nuance: **two distinct transient objects that happen to share the same natural id value are
|
||||
already `equals()` to each other, before either is persisted.** [`NaturalIdEqualsHashSetTest`](../src/test/java/com/ankurm/hibernatedemo/naturalid/NaturalIdEqualsHashSetTest.java)
|
||||
shows a `HashSet.add()` on a second transient instance with the same `sku` but a different
|
||||
`name` is silently rejected as a duplicate. That is usually the intended behavior (natural ids
|
||||
are supposed to be unique business keys), but it means natural-id-based equality can mask a bug
|
||||
where two *meant-to-be-different* objects were accidentally constructed with the same business
|
||||
key before either ever reached the database — a failure mode the surrogate-id approach cannot
|
||||
produce (two transient surrogate-id objects are never accidentally "the same" via `equals()`
|
||||
unless you specifically wrote id-based equality, which the article correctly warns against for
|
||||
other reasons).
|
||||
|
||||
## Numbers summary
|
||||
|
||||
| Scenario | Queries | Cache hits/misses | Source |
|
||||
|---|---|---|---|
|
||||
| No L2, `bySimpleNaturalId` x2, same session | 1, then 1 (0 new) | n/a | `naturalid-tests.txt` |
|
||||
| No L2, `bySimpleNaturalId`, new session | 1, then 2 cumulative (+1) | n/a | `naturalid-tests.txt` |
|
||||
| `@NaturalIdCache`, insert then 2 lookups (own inserts) | 0 additional after insert | 2 hits, 0 miss | `naturalid-tests.txt` |
|
||||
| `@NaturalIdCache`, row inserted outside Hibernate | 1 (miss), then 1 cumulative (0 new) | 1 miss+put, then 1 hit | `naturalid-tests.txt` |
|
||||
| Composite natural id lookup | 1 | n/a | `naturalid-tests.txt` |
|
||||
|
||||
All counts measured via `SessionFactory.getStatistics()` in this sandbox; treat absolute timings
|
||||
as indicative only, but the query *counts* are exact and reproducible (deterministic, not
|
||||
timing-based).
|
||||
|
||||
The three natural-id entry points on `Session`, read straight off the jar, are in [`docs/output/naturalid-javap-session.txt`](output/naturalid-javap-session.txt).
|
||||
|
||||
[← Previous: 05 — JPA persistence annotations](05-jpa-persistence-annotations.md) | [Next: 07 — Immutable entities →](07-immutable-entities.md)
|
||||
Executable
+130
@@ -0,0 +1,130 @@
|
||||
# 07 — `@Immutable` entities in Hibernate 7 (post 4866)
|
||||
|
||||
[← Previous: 06 — Natural IDs](06-natural-ids.md) | [Next: 08 — Stored procedures →](08-stored-procedures.md)
|
||||
|
||||
Backs [ankurm.com: Hibernate 7 immutable entities](https://ankurm.com/mastering-hibernate-7-immutable-entities-performance-safety-and-best-practices/).
|
||||
Verified on Hibernate ORM 7.4.5.Final, jakarta.persistence-api 3.2.0,
|
||||
H2 2.4.240, JDK 25 (Temurin 25.0.4.1).
|
||||
|
||||
Test classes: [`ImmutableEntityTest`](../src/test/java/com/ankurm/hibernatedemo/ImmutableEntityTest.java),
|
||||
[`ImmutableBulkUpdateAllowedTest`](../src/test/java/com/ankurm/hibernatedemo/ImmutableBulkUpdateAllowedTest.java),
|
||||
[`ImmutableFlushCostTest`](../src/test/java/com/ankurm/hibernatedemo/ImmutableFlushCostTest.java).
|
||||
Entities: [`immutable/`](../src/main/java/com/ankurm/hibernatedemo/immutable/).
|
||||
|
||||
```bash
|
||||
./mvnw -Dtest=ImmutableEntityTest,ImmutableBulkUpdateAllowedTest,ImmutableFlushCostTest test
|
||||
```
|
||||
|
||||
Raw captured output:
|
||||
[`immutable-headline-and-boundaries.txt`](output/immutable-headline-and-boundaries.txt),
|
||||
[`immutable-javap-annotation.txt`](output/immutable-javap-annotation.txt).
|
||||
|
||||
## What `@Immutable` actually is, per the class file
|
||||
|
||||
`javap -v org.hibernate.annotations.Immutable` (Hibernate ORM 7.4.5.Final) shows it targets
|
||||
`TYPE`, `METHOD`, `FIELD` and carries **zero annotation members** — no `value()`, nothing to
|
||||
configure. It's a pure marker. That matches how the source articles use it, but is worth stating
|
||||
precisely: there is no per-field opt-out, no "immutable except this column" mode. Immutability at
|
||||
the entity level is all-or-nothing; the granularity you get is choosing which *fields* or which
|
||||
*collection* to put the annotation on, not tuning behaviour within one.
|
||||
|
||||
## The headline behaviour: silence, not an exception
|
||||
|
||||
Mutate a managed `@Immutable` entity's field and flush inside a transaction. Nothing happens —
|
||||
literally nothing observable. No `UPDATE` is sent (`Statistics.getEntityUpdateCount()` stays at
|
||||
`0`), and `commit()` does not throw. The row you reload afterwards is untouched. This is the part
|
||||
worth building intuition around: `@Immutable` is not a guard that rejects writes, it's a filter
|
||||
that makes Hibernate blind to them. If you were expecting a `StaleStateException` or a validation
|
||||
failure when someone accidentally mutates one of these entities, you will not get one — you get
|
||||
quiet data loss of the in-memory change, and the database keeps whatever it already had.
|
||||
|
||||
## The three things `@Immutable` does NOT stop
|
||||
|
||||
Verified independently, each behaving differently:
|
||||
|
||||
- **`EntityManager.remove()` / DELETE** — goes through normally. `@Immutable` only removes the
|
||||
entity from *dirty-checking*; it says nothing about the persister's ability to issue a DELETE
|
||||
when you explicitly ask for one.
|
||||
- **Native SQL** — always works, unconditionally. Native SQL never goes through Hibernate's
|
||||
entity-state machinery at all, so there is no layer for `@Immutable` to intercept.
|
||||
- **Bulk HQL `update ... set ...`** — this is the one correction to make explicitly, because the
|
||||
intuitive answer is wrong. It is tempting to assume bulk HQL bypasses `@Immutable` the same way
|
||||
native SQL does (both skip per-entity dirty checking). It does not: Hibernate 7.4.5 refuses to
|
||||
even *translate* the query, at HQL-compile time, before touching the database:
|
||||
|
||||
```
|
||||
org.hibernate.query.sqm.InterpretationException: Error interpreting query
|
||||
[The query attempts to update an immutable entity: [exchange_rate]
|
||||
(set 'hibernate.query.immutable_entity_update_query_handling_mode' to suppress)]
|
||||
```
|
||||
|
||||
The property named in the message,
|
||||
`org.hibernate.cfg.QuerySettings.IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE`
|
||||
(`hibernate.query.immutable_entity_update_query_handling_mode`), is a `SessionFactory`-wide
|
||||
three-way enum: `EXCEPTION` (default), `WARNING`, `ALLOW`. Set to `ALLOW`, the bulk update
|
||||
actually executes against the immutable table — verified in
|
||||
`ImmutableBulkUpdateAllowedTest`, a separate Spring context with the property set, since it is
|
||||
not a per-query hint. Bulk DELETE via HQL, by contrast, is not blocked at all — only bulk
|
||||
UPDATE has this guard.
|
||||
|
||||
## `@Immutable` on a collection
|
||||
|
||||
Putting `@Immutable` on a `@OneToMany` is a *separate* annotation usage from putting it on the
|
||||
owning entity — you can have a mutable parent with an immutable child collection (that's what
|
||||
`RateWithAuditTrail` demonstrates). Adding an element to that collection and flushing throws, and
|
||||
the exact shape matters if you're writing a catch clause: the immediate exception is
|
||||
`jakarta.persistence.RollbackException` wrapping the transaction commit, and its root cause is a
|
||||
plain `org.hibernate.HibernateException` (not a dedicated subclass) with the message:
|
||||
|
||||
```
|
||||
Immutable collection was modified: [<Entity>.<collection> with owner id '<id>']
|
||||
```
|
||||
|
||||
Catch `HibernateException` (or inspect the cause chain), not a more specific type — there isn't
|
||||
one.
|
||||
|
||||
## `@Immutable` + `@Version`
|
||||
|
||||
Hibernate 7.4.5 accepts the combination without a startup error. It is exactly as inert as the
|
||||
source article warns: the version column is written once at INSERT (starting at `0`) and never
|
||||
increments afterward, because there is no UPDATE for it to ride along on. This isn't a distinct
|
||||
code path from the headline case — it's the same "flush sees a null snapshot, skips the entity
|
||||
entirely" mechanism, applied to an entity that happens to also carry a `@Version` field.
|
||||
|
||||
## `@Immutable` vs `Session.setReadOnly()` / `setDefaultReadOnly()`
|
||||
|
||||
Both `Session.setReadOnly(entity, true)` (per-instance) and `Session.setDefaultReadOnly(true)`
|
||||
(session-wide default for everything loaded after the call) produce the *same observable
|
||||
outcome* as `@Immutable` on a mutated-and-flushed entity: zero `UPDATE`s, no exception. The
|
||||
difference is entirely about *when* the decision is made and *how durable* it is:
|
||||
|
||||
| | `@Immutable` | `setReadOnly()` / `setDefaultReadOnly()` |
|
||||
|---|---|---|
|
||||
| Scope | Class-level, every instance, every session | Per entity instance, or per session |
|
||||
| Decided | At mapping time (compile time) | At runtime, per `Session` |
|
||||
| Reversible | No (would need a redeploy) | Yes, per instance or per session |
|
||||
| Cost paid | Never allocates a snapshot at all | Still allocates the snapshot; the read-only flag is checked at flush instead |
|
||||
|
||||
That cost line is the one worth measuring rather than asserting. `ImmutableFlushCostTest` loads
|
||||
4,000 rows of a 12-column entity (both `@Immutable` and plain, no pending changes) into a fresh
|
||||
persistence context and times a single `flush()` around the load. On this sandbox (a shared
|
||||
container — treat as indicative of direction and rough magnitude, not a citable number), flushing
|
||||
the mutable set took **~8.5ms**; the `@Immutable` set took **~1.9–2.5ms** across two runs — a
|
||||
**3.4×–4.5× difference**, purely from Hibernate having a snapshot to compare 12 fields against on
|
||||
one side and nothing to check at all on the other. `setReadOnly()`/`setDefaultReadOnly()` sit
|
||||
architecturally on the "still allocates a snapshot" side of that line — they suppress the
|
||||
*write*, not the *snapshot allocation and comparison* `@Immutable` skips outright. Confirming that
|
||||
distinction with a clean timing delta would need a dedicated benchmark isolating snapshot
|
||||
allocation specifically; this test measures the flush-time symptom, not the allocation itself, so
|
||||
say that plainly rather than overclaiming a mechanism from a flush timing.
|
||||
|
||||
## Practical takeaway
|
||||
|
||||
`@Immutable` is a mapping-time, all-instances, unconditional decision. Reach for it for data that
|
||||
is *architecturally* never going to change (reference data, audit rows, historical snapshots).
|
||||
Reach for `Session.setReadOnly()` instead when the read-only-ness is a *per-request* or
|
||||
*per-session* decision — a reporting query that happens to load entities it has no business
|
||||
writing back, for instance — where you want the same flush suppression without committing the
|
||||
entity class itself to being permanently immutable.
|
||||
|
||||
[← Previous: 06 — Natural IDs](06-natural-ids.md) | [Next: 08 — Stored procedures →](08-stored-procedures.md)
|
||||
Executable
+183
@@ -0,0 +1,183 @@
|
||||
# 08 — Stored procedures with Hibernate 7 (merges posts 4867 + 4881)
|
||||
|
||||
[← Previous: 07 — Immutable entities](07-immutable-entities.md) | [Next: 09 — Testing with in-memory databases →](09-testing-in-memory-databases.md)
|
||||
|
||||
Backs [ankurm.com: stored procedures with Hibernate 7](https://ankurm.com/mastering-stored-procedures-with-hibernate-7-a-deep-dive-for-high-performance-java-apps/).
|
||||
|
||||
Posts 4867 (`@NamedStoredProcedureQuery`) and 4881 (general stored-procedure guide) cover the
|
||||
same ground from two angles — annotation-driven metadata and the programmatic
|
||||
`StoredProcedureQuery` API — and both demo a MySQL `DELIMITER //` procedure that was never
|
||||
actually run. This chapter merges them into one topic and, for the first time, executes every
|
||||
example against a real database: **HSQLDB 2.7.3**, which supports genuine SQL/PSM
|
||||
`CREATE PROCEDURE` with IN/OUT/INOUT parameters and cursor-backed result sets.
|
||||
|
||||
Verified on Hibernate ORM 7.4.5.Final, jakarta.persistence-api 3.2.0, HSQLDB 2.7.3, JDK 25.
|
||||
|
||||
Test classes:
|
||||
[`StoredProcedureHappyPathTest`](../src/test/java/com/ankurm/hibernatedemo/procedure/StoredProcedureHappyPathTest.java),
|
||||
[`ProcedureFailureModesTest`](../src/test/java/com/ankurm/hibernatedemo/procedure/ProcedureFailureModesTest.java),
|
||||
[`ProcedureSchemaSupport`](../src/test/java/com/ankurm/hibernatedemo/procedure/ProcedureSchemaSupport.java)
|
||||
(the real `CREATE PROCEDURE` DDL). Entities:
|
||||
[`procedure/`](../src/main/java/com/ankurm/hibernatedemo/procedure/) —
|
||||
[`ProcEmployee`](../src/main/java/com/ankurm/hibernatedemo/procedure/ProcEmployee.java),
|
||||
[`EmployeeSummary`](../src/main/java/com/ankurm/hibernatedemo/procedure/EmployeeSummary.java).
|
||||
|
||||
```bash
|
||||
./mvnw -Dtest=StoredProcedureHappyPathTest,ProcedureFailureModesTest test
|
||||
```
|
||||
|
||||
Raw output: [`procedure-happy-path.txt`](output/procedure-happy-path.txt),
|
||||
[`procedure-failure-modes.txt`](output/procedure-failure-modes.txt),
|
||||
[`procedure-hsqldb-jdbc-driver-quirk.txt`](output/procedure-hsqldb-jdbc-driver-quirk.txt),
|
||||
[`procedure-javap-api-surface.txt`](output/procedure-javap-api-surface.txt).
|
||||
|
||||
## The API surface, confirmed by javap, not by reading docs
|
||||
|
||||
`jakarta.persistence-api-3.2.0.jar` really does contain `NamedStoredProcedureQuery`,
|
||||
`StoredProcedureParameter`, and `StoredProcedureQuery` exactly where both articles say. All
|
||||
three parameter modes (`IN`, `OUT`, `INOUT`) plus `REF_CURSOR` exist on `ParameterMode`. This
|
||||
part of the articles was accurate; it just needed a receipt.
|
||||
|
||||
## IN / OUT — three call styles, same real result
|
||||
|
||||
A single HSQLDB procedure, `GET_TAX(IN emp_id INT, OUT tax_amount DECIMAL(10,2))`, computing
|
||||
`salary * 0.15`, was called three ways and produced the same live database result each time
|
||||
([`docs/output/procedure-happy-path.txt`](output/procedure-happy-path.txt)):
|
||||
|
||||
- `@NamedStoredProcedureQuery` + `EntityManager.createNamedStoredProcedureQuery(name)`
|
||||
- unnamed, via `EntityManager.createStoredProcedureQuery("GET_TAX")` +
|
||||
`registerStoredProcedureParameter(...)`
|
||||
- unnamed, via `Session.createStoredProcedureQuery("GET_TAX")` (Hibernate-native entry point,
|
||||
same JPA-shaped return type)
|
||||
|
||||
Employee id 1, salary 50,000.00 → tax **7,500.00**, exactly as the (previously unexecuted)
|
||||
article predicted.
|
||||
|
||||
## INOUT — round-trips through the same parameter slot
|
||||
|
||||
`ADJUST_SALARY(INOUT sal DECIMAL(10,2), IN bonus_pct DECIMAL(5,2))` takes 1,000.00 and 10%,
|
||||
returns **1,100.00** through `getOutputParameterValue("sal")` — the same parameter object used
|
||||
for both the input bind and the output read. This confirms the articles' basic INOUT claim; the
|
||||
part they didn't cover is what happens when you get the setup wrong (see Pitfalls below).
|
||||
|
||||
## Result sets: where Hibernate + HSQLDB genuinely does not work
|
||||
|
||||
This needed to be said plainly rather than faked. A `DYNAMIC RESULT SETS 1` procedure that opens
|
||||
a cursor (`LIST_EMPLOYEES()`) works perfectly over raw JDBC — `CallableStatement.executeQuery()`
|
||||
returns the rows without complaint. But Hibernate's `ProcedureCallImpl` doesn't call
|
||||
`executeQuery()`; it calls `execute()` and trusts its boolean return to decide whether a
|
||||
`ResultSetOutput` exists. A raw-JDBC probe isolates the exact defect:
|
||||
|
||||
```
|
||||
execute() returned=false <- HSQLDB driver says "no result set"
|
||||
getResultSet() = <live ResultSet with 2 rows> <- but there is one
|
||||
```
|
||||
|
||||
Because Hibernate believes the (wrong) `false`, both `@NamedStoredProcedureQuery(resultClasses =
|
||||
ProcEmployee.class)` and `createStoredProcedureQuery(name, "EmployeeSummaryMapping")` (the
|
||||
`@SqlResultSetMapping`-to-DTO path) fail identically:
|
||||
|
||||
```
|
||||
java.lang.IllegalStateException: Current CallableStatement was not a ResultSet, but getResultList was called
|
||||
```
|
||||
|
||||
**This is a real HSQLDB-JDBC-driver incompatibility, not a mapping mistake** — verified by
|
||||
reproducing the underlying JDBC behaviour outside Hibernate entirely
|
||||
([`docs/output/procedure-hsqldb-jdbc-driver-quirk.txt`](output/procedure-hsqldb-jdbc-driver-quirk.txt)). It blocks the "map a procedure's result
|
||||
set to an entity" and "map it to a DTO via `@SqlResultSetMapping`" scenarios specifically on
|
||||
HSQLDB + Hibernate 7.4.5. A database whose driver reports `execute()` correctly for cursor
|
||||
results — PostgreSQL's REF_CURSOR support, or MySQL/SQL Server's direct-result-set procedures —
|
||||
would not hit this; a real PostgreSQL REF_CURSOR run was not attempted in this pass (treated as
|
||||
optional per scope) and would be the natural follow-up if this chapter needs the mapped-result-set
|
||||
demo running end-to-end.
|
||||
|
||||
One incidental, useful finding from the same probe: HSQLDB does **not** enforce the classic
|
||||
"consume the result set before reading OUT parameters" ordering rule some drivers impose. On a
|
||||
procedure with both an OUT parameter and a cursor, the OUT value reads correctly whether you read
|
||||
it before, interleaved with, or after draining the cursor. That specific folklore pitfall is real
|
||||
on some databases, not on this one — worth saying explicitly rather than repeating as universal.
|
||||
|
||||
## The failure modes (the actual point of this chapter)
|
||||
|
||||
All verbatim, from `ProcedureFailureModesTest`:
|
||||
|
||||
- **Wrong parameter name, right position** — registering a parameter under a name the procedure
|
||||
does not have (`"employee_id"` vs. the real `"emp_id"`) **does not fail and does not silently
|
||||
null out**. HSQLDB's driver calls procedures with positional `{call GET_TAX(?, ?)}` syntax —
|
||||
the name never reaches the database. Hibernate maps `registerStoredProcedureParameter(name,
|
||||
...)` to the Nth JDBC placeholder by **registration order**, and `name` is purely a client-side
|
||||
label for later `setParameter`/`getOutputParameterValue` calls. The call still returns the
|
||||
correct 7,500.00. The corollary: **parameter order is the thing that must be right; the name is
|
||||
cosmetic** for a driver like this one. This directly validates the one piece of caution the
|
||||
original article got right ("ensure the order... matches the database definition") while
|
||||
correcting the implicit assumption that a name mismatch would be caught.
|
||||
- **`ParameterMode` mismatch** — registering the real IN parameter as `OUT` throws immediately at
|
||||
registration/bind time:
|
||||
`org.hibernate.exception.GenericJDBCException: Unable to register CallableStatement OUT
|
||||
parameter [Invalid argument in JDBC call: Not OUT or INOUT mode for parameter: 1]`. Swapping
|
||||
the IN/OUT slots by position produces the identical error — this is the one failure mode that
|
||||
*does* fail loudly and immediately, unlike the name mismatch above.
|
||||
- **`getResultList()` on a procedure with no result set** — throws the exact same
|
||||
`IllegalStateException: Current CallableStatement was not a ResultSet, but getResultList was
|
||||
called` as the HSQLDB result-set incompatibility above. Same exception, two different causes
|
||||
(one is a real absence of a result set, the other is a driver misreporting one that exists) —
|
||||
worth knowing they're indistinguishable from the exception alone.
|
||||
- **"Forgetting" `execute()`** — corrects another assumption. Calling
|
||||
`getOutputParameterValue()` without an explicit `execute()` call first does **not** throw
|
||||
"you forgot to call execute()". Hibernate's `ProcedureCallImpl` lazily triggers the JDBC
|
||||
execution itself the first time an output is requested, and returns the correct value. The
|
||||
"forgetting execute()" pitfall from blog folklore is not reproducible against Hibernate
|
||||
7.4.5's `StoredProcedureQuery` for OUT-parameter access.
|
||||
|
||||
## Flush behaviour and the persistence context — the important trap, confirmed
|
||||
|
||||
Persisting a new row and calling a procedure that counts rows **in the same transaction, without
|
||||
an explicit flush**, does **not** see the new row:
|
||||
|
||||
```
|
||||
COUNT_EMPLOYEES before persisting a new row = 2
|
||||
COUNT_EMPLOYEES after persist() but WITHOUT an explicit flush() = 2
|
||||
COUNT_EMPLOYEES after an explicit flush() = 3
|
||||
```
|
||||
|
||||
Stored procedure calls do not trigger Hibernate's usual auto-flush-before-query behaviour. This
|
||||
matters because HQL, Criteria, and even plain native queries against a synchronized entity/table
|
||||
normally DO auto-flush first. A second test closes the obvious escape hatch: the Hibernate-native
|
||||
`ProcedureCall`'s `addSynchronizedEntityClass(...)` — documented, for HQL/native queries, to force
|
||||
exactly this kind of auto-flush — has **no effect** when called on a `ProcedureCall`. An unflushed
|
||||
`persist()` stayed invisible to `COUNT_EMPLOYEES` even after declaring the synchronization. The
|
||||
practical rule: **always flush explicitly before calling a stored procedure that needs to see
|
||||
pending changes in the same transaction; there is no annotation-level escape hatch.**
|
||||
|
||||
Cache implications (2LC / query cache) were not independently re-measured here beyond confirming
|
||||
the flush behaviour above — the FAQ claim that mutating procedures leave L2 cache entries stale
|
||||
until manually evicted is consistent with the "no auto-flush, no auto-invalidate" pattern observed
|
||||
and is the safe assumption to keep in the merged chapter.
|
||||
|
||||
## `ProcedureCall` (Hibernate-native) vs `StoredProcedureQuery` (JPA)
|
||||
|
||||
`javap org.hibernate.procedure.ProcedureCall` ([`docs/output/procedure-javap-api-surface.txt`](output/procedure-javap-api-surface.txt))
|
||||
confirms it extends `jakarta.persistence.StoredProcedureQuery` — every JPA method is available —
|
||||
and adds, among others:
|
||||
|
||||
- `markAsFunctionCall(Class<?> | int | Type<?>)` — calling a database **function**, not just a
|
||||
procedure, something the JPA-standard `StoredProcedureQuery` has no direct concept of.
|
||||
`FUNCTION_RETURN_TYPE_HINT` backs this.
|
||||
`getFunctionReturn()` retrieves the typed function result separately from OUT parameters.
|
||||
- `addSynchronizedQuerySpace(String)` / `addSynchronizedEntityName(String)` /
|
||||
`addSynchronizedEntityClass(Class)` — inherited from `SynchronizeableQuery`; present on the
|
||||
native API but (per above) inert for auto-flush purposes on procedure calls specifically.
|
||||
- Typed parameter registration via `jakarta.persistence.metamodel.Type<T>` in addition to
|
||||
`Class<T>`, and `getRegisteredParameters()` / `getParameterRegistration(...)` for introspecting
|
||||
what's already bound.
|
||||
- `AutoCloseable` — `ProcedureCall` can be used in try-with-resources; `StoredProcedureQuery`
|
||||
cannot.
|
||||
|
||||
For portable, Jakarta-EE-standard code, `EntityManager.createStoredProcedureQuery(...)` /
|
||||
`@NamedStoredProcedureQuery` is the right default — everything in the "happy path" section above
|
||||
works identically through it. Reach for `Session.createStoredProcedureCall(...)` specifically for
|
||||
function calls (`markAsFunctionCall`) or when you need to introspect parameter registrations
|
||||
programmatically; do not reach for it expecting `addSynchronizedEntityClass` to save you a
|
||||
manual `flush()`.
|
||||
|
||||
[← Previous: 07 — Immutable entities](07-immutable-entities.md) | [Next: 09 — Testing with in-memory databases →](09-testing-in-memory-databases.md)
|
||||
Executable
+247
@@ -0,0 +1,247 @@
|
||||
# 09 — In-memory databases for testing: H2, HSQLDB and Derby, run side by side and verified
|
||||
|
||||
[← Previous: 08 — Stored procedures](08-stored-procedures.md) | [Next: 10 — Mocking JNDI datasources →](10-mocking-jndi-datasources.md)
|
||||
|
||||
Backs [ankurm.com: configuring in-memory databases for bulletproof unit testing](https://ankurm.com/master-hibernate-7-configuring-in-memory-databases-for-bulletproof-unit-testing/).
|
||||
|
||||
Companion code: [`TestDbWidget`](../src/main/java/com/ankurm/hibernatedemo/testdb/TestDbWidget.java) (one entity,
|
||||
run against all three engines) and [`src/test/java/com/ankurm/hibernatedemo/testdb/`](../src/test/java/com/ankurm/hibernatedemo/testdb/) (six test
|
||||
classes, 16 tests, all green together -- `docs/output/testdb-*.txt`). Environment: Hibernate ORM
|
||||
7.4.5.Final, JDK 25, H2 2.4.240, HSQLDB 2.7.3, Apache Derby 10.16.1.1. All three bootstrapped
|
||||
directly through plain Hibernate (`StandardServiceRegistryBuilder`/`MetadataSources`), not
|
||||
through Spring Boot's single-datasource autoconfiguration, specifically so all three could be
|
||||
stood up side by side against the exact same mapping without needing three separate Spring
|
||||
contexts.
|
||||
|
||||
## Headline correction: Derby has no dialect in Hibernate 7 without an extra dependency
|
||||
|
||||
This is the biggest surprise in this chapter, and it isn't in the article being replaced at all.
|
||||
Wiring up Derby against Hibernate 7.4.5.Final the "obvious" way fails, twice, in sequence:
|
||||
|
||||
1. With no `hibernate.dialect` set (which works fine for both H2 and HSQLDB, relying on JDBC
|
||||
metadata auto-detection): `Unable to determine Dialect for Apache Derby 10.16 (please set
|
||||
'hibernate.dialect' or register a Dialect resolver)`. The JDBC connection itself is fine --
|
||||
the product name and version ("Apache Derby 10.16") were read successfully. Hibernate's
|
||||
dialect resolver chain simply no longer recognizes it.
|
||||
2. The "obvious" fix -- set `hibernate.dialect=org.hibernate.dialect.DerbyDialect`, the FQCN
|
||||
every existing blog post and Stack Overflow answer uses -- fails too:
|
||||
`ClassNotFoundException: Could not load requested class: org.hibernate.dialect.DerbyDialect`.
|
||||
That class does not exist anywhere in `hibernate-core-7.4.5.Final.jar` (confirmed:
|
||||
`unzip -l ... | grep -i derby` -- zero matches).
|
||||
|
||||
Hibernate 6.2+ moved a set of less-common dialects out of `hibernate-core` into a separate,
|
||||
opt-in artifact, `org.hibernate.orm:hibernate-community-dialects`. Derby's dialect now lives
|
||||
there, under a **different package**: `org.hibernate.community.dialect.DerbyDialect` (confirmed
|
||||
present via `unzip -l hibernate-community-dialects-7.4.5.Final.jar | grep -i derby`). Both
|
||||
failures, verbatim, and the working fix are in
|
||||
[`docs/output/testdb-derby-dialect-not-found.txt`](output/testdb-derby-dialect-not-found.txt). The dependency this needed is already wired into this
|
||||
repo's shared [`pom.xml`](../pom.xml):
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.hibernate.orm</groupId>
|
||||
<artifactId>hibernate-community-dialects</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
With that dependency and `hibernate.dialect=org.hibernate.community.dialect.DerbyDialect` set
|
||||
explicitly, Derby resolves and works completely normally for everything else in this chapter.
|
||||
|
||||
## `hibernate-jcache` on the classpath turns on L2 for everyone, whether you asked or not
|
||||
|
||||
This is the second headline finding in this chapter, and it is not scoped to Derby, or even to
|
||||
testing in-memory databases specifically -- it is a repo-wide gotcha that this chapter is the
|
||||
right place to document because [`JCacheOnClasspathAutoEnablesL2Test`](../src/test/java/com/ankurm/hibernatedemo/testdb/JCacheOnClasspathAutoEnablesL2Test.java) lives in this package.
|
||||
Chapter 06 needs `hibernate-jcache` + `ehcache` on the classpath to measure `@NaturalIdCache`
|
||||
(see [chapter 06](06-natural-ids.md#turning-on-l2-hibernate-jcache--ehcache)), and that dependency
|
||||
is shared across the whole project's single `pom.xml` -- there's no way to scope it to only the
|
||||
natural-id tests.
|
||||
|
||||
`JCacheOnClasspathAutoEnablesL2Test` boots a bare `SessionFactory` with **zero** cache settings
|
||||
configured anywhere -- no `hibernate.cache.*` property, no `@Cache`/`@NaturalIdCache` annotation
|
||||
in sight -- and finds:
|
||||
|
||||
```
|
||||
second-level cache enabled = true
|
||||
region factory = org.hibernate.cache.jcache.internal.JCacheRegionFactory
|
||||
```
|
||||
|
||||
Hibernate 7.4.5 resolves a `RegionFactory` through the `ServiceLoader` at boot, and merely
|
||||
*finding one on the classpath* is enough for it to turn the second-level cache on by itself.
|
||||
There is no explicit configuration anywhere that asks for this -- `grep -ic cache` against
|
||||
[`application.yml`](../src/main/resources/application.yml) before this was pinned down returned `0`.
|
||||
|
||||
This was not a hypothetical risk -- it broke a real, unrelated test. Before
|
||||
`hibernate.cache.use_second_level_cache: false` was pinned explicitly in `application.yml`, a
|
||||
full `mvn test` run failed with an order-dependent error: a standalone natural-id-cache test
|
||||
closed the shared Ehcache `CacheManager` it had spun up, and the next Spring-context test to
|
||||
commit a transaction failed with `Cache[...] is closed`, verbatim in
|
||||
[`docs/output/testdb-jcache-classpath-pollution.txt`](output/testdb-jcache-classpath-pollution.txt):
|
||||
|
||||
```
|
||||
[ERROR] ImmutableEntityTest.nativeSqlUpdate_onImmutableEntity_alwaysWorks:184 » Rollback Error while committing the transaction [Unable to perform afterTransactionCompletion callback: Cache[com.ank
|
||||
```
|
||||
|
||||
The fix is the explicit pin in `application.yml`:
|
||||
|
||||
```yaml
|
||||
hibernate:
|
||||
cache:
|
||||
use_second_level_cache: false
|
||||
```
|
||||
|
||||
Not "leave it unset and hope no cache provider ever lands on the classpath" -- an unset value in
|
||||
this codebase resolves to `true` the moment `hibernate-jcache` is present, regardless of intent.
|
||||
Any project that adds `hibernate-jcache` (or any other JCache/Ehcache/Infinispan provider) for
|
||||
one narrow use case should assume it just turned L2 on globally unless it pins the setting back
|
||||
down explicitly, the same way this repo does.
|
||||
|
||||
## Dialect auto-selection, confirmed for all three (`DialectAndDdlTest`)
|
||||
|
||||
| Database | Resolved `Dialect` class |
|
||||
|---|---|
|
||||
| H2 (plain) | `org.hibernate.dialect.H2Dialect` |
|
||||
| H2 `MODE=PostgreSQL` | `org.hibernate.dialect.H2Dialect` |
|
||||
| H2 `MODE=Oracle` | `org.hibernate.dialect.H2Dialect` |
|
||||
| HSQLDB | `org.hibernate.dialect.HSQLDialect` |
|
||||
| Derby | `org.hibernate.community.dialect.DerbyDialect` (explicit setting required, see above) |
|
||||
|
||||
## The MODE= question, settled
|
||||
|
||||
This is the single most misunderstood H2 feature, and the answer is unambiguous once you
|
||||
actually build a `SessionFactory` against each URL and read off the resolved `Dialect` class
|
||||
(`DialectAndDdlTest.h2WithPostgresModeInTheUrl_...` / `...OracleMode...`, both green): **`MODE=`
|
||||
changes what SQL H2 itself will parse and accept -- it does not change which Hibernate `Dialect`
|
||||
class gets selected.** Hibernate's dialect resolution reads the JDBC driver's own
|
||||
`DatabaseMetaData.getDatabaseProductName()`, and H2 reports itself as `H2` regardless of the
|
||||
`MODE=` parameter in the URL. `H2Dialect` is what generates DDL and SQL in all three cases; the
|
||||
resulting `create table` statements in [`docs/output/testdb-create-table-ddl.txt`](output/testdb-create-table-ddl.txt) are
|
||||
byte-for-byte identical across plain H2, `MODE=PostgreSQL` and `MODE=Oracle`. If you need
|
||||
Hibernate to actually emit PostgreSQL- or Oracle-flavoured SQL, you set `hibernate.dialect`
|
||||
yourself; `MODE=` alone will not do it, and testing against H2 in a given `MODE=` is not the
|
||||
same thing as testing against `PostgreSQLDialect`.
|
||||
|
||||
## Generated DDL, and where it turned out to be identical, not different
|
||||
|
||||
The same `TestDbWidget` mapping (`GenerationType.AUTO` id, `varchar(5)` SKU, an `@Lob` clob
|
||||
description, a `boolean`, and a reserved-word-shaped column defensively quoted as `"order"`)
|
||||
produces **textually identical** `create table` and `create sequence` statements across H2,
|
||||
HSQLDB and Derby ([`docs/output/testdb-create-table-ddl.txt`](output/testdb-create-table-ddl.txt)):
|
||||
|
||||
```sql
|
||||
create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
```
|
||||
|
||||
This corrects an assumption going in: the expectation was to find `varchar` vs `character
|
||||
varying`, or different boolean/clob keyword choices, across these three specific engines.
|
||||
They didn't diverge -- all three dialects happen to accept the same ANSI-shaped keywords
|
||||
(`boolean`, `varchar(n)`, `clob`) for this particular mapping. The real divergence, it turned
|
||||
out, is not in the DDL keywords Hibernate chooses, but in which *identifiers* each engine's
|
||||
parser accepts unquoted -- see below.
|
||||
|
||||
## `GenerationType.AUTO`: identical across all three here
|
||||
|
||||
`AUTO` resolved to a native `SEQUENCE` (`TestDbWidget_SEQ`, allocation size 50) on **all three**
|
||||
engines -- H2, HSQLDB and Derby all support native sequences, so Hibernate 7 has no reason to
|
||||
fall back to `TABLE` or `IDENTITY` for any of them. This is worth stating plainly because AUTO's
|
||||
reputation for being unpredictable comes from databases like MySQL that lack native sequences
|
||||
entirely; for this specific trio, AUTO does not actually diverge.
|
||||
|
||||
## The concrete cross-database failure case, proven with real SQL (`CrossDatabaseBehaviorTest`)
|
||||
|
||||
The brief for this chapter specifically asked for a genuine "passes on X, fails on Y" case, not
|
||||
a folklore restatement. Two were found, one confirmed and one corrected:
|
||||
|
||||
**Reserved-word divergence -- real, and NOT the word you'd expect.** The obvious first guess,
|
||||
an unquoted `order` column, turned out to be the wrong probe: H2, HSQLDB and Derby all reject it
|
||||
identically ([`docs/output/testdb-reserved-word-survey.txt`](output/testdb-reserved-word-survey.txt), a 22-word survey run to find one
|
||||
that actually diverges). The word that genuinely splits the three: **`value`**. H2 rejects an
|
||||
unquoted `value` column outright:
|
||||
|
||||
```
|
||||
JdbcSQLSyntaxErrorException: Syntax error in SQL statement "create table reserved_word_test (id integer, [*]value integer)"; expected "identifier"
|
||||
```
|
||||
|
||||
HSQLDB and Derby both accept it without complaint. An entity field named `value` with no
|
||||
`@Column(name = "\"value\"")` escaping builds a working schema on two of these three engines and
|
||||
throws a SQL syntax error, specifically on H2 -- the reverse of what most people would guess,
|
||||
since H2 has a reputation as the "permissive" one.
|
||||
|
||||
**CHAR padding -- real, but NOT Derby-exclusive, contrary to widely-repeated folklore.** The
|
||||
brief called this "a classic Derby thing." Measured directly (`CHAR(10)` holding `'AB'`, read
|
||||
back via `ResultSet.getString()`): H2, HSQLDB and Derby **all** return `"AB "` (length
|
||||
10, space-padded) -- not just Derby. A naive `"AB".equals(value)` fails against all three
|
||||
engines for a `CHAR` column; only `VARCHAR` avoids the padding. The trap is real and worth
|
||||
keeping in the article; attributing it to Derby specifically is not.
|
||||
|
||||
## Schema isolation: pollution proven, then the fix proven (`SchemaIsolationTest`)
|
||||
|
||||
Four ordered tests against one shared `SessionFactory`, deliberately built to show both failure
|
||||
and fix in the same run:
|
||||
|
||||
1. `testA` inserts a row and does nothing to clean up.
|
||||
2. `testB` -- which inserts nothing itself -- immediately sees `count >= 1`. The leftover row
|
||||
from `testA` is visible because nothing isolated the two tests from each other.
|
||||
3. `testC` inserts a row inside a transaction, then **rolls back** instead of committing.
|
||||
4. `testD` looks specifically for `testC`'s row by its unique SKU and finds zero -- rollback
|
||||
isolated it completely.
|
||||
|
||||
`create-drop` (used to build the shared `SessionFactory` here) only isolates at the
|
||||
*SessionFactory* level -- one schema for the whole test class's lifetime, dropped and recreated
|
||||
once. It does nothing to isolate individual *tests* from each other; that isolation has to come
|
||||
from something else -- a transaction rolled back per test (what `testC`/`testD` show, and what
|
||||
Spring's `@Transactional` does for you automatically in `@SpringBootTest` classes), or a full
|
||||
`create-drop` re-run per test method (correct, but noticeably slower since it re-creates the
|
||||
whole schema every time), or a fresh `@DirtiesContext`-forced new `ApplicationContext` (correct,
|
||||
but the heaviest option of the three since it rebuilds the entire Spring context, not just the
|
||||
schema).
|
||||
|
||||
## `DB_CLOSE_DELAY=-1`, proven with a before/after (`DbCloseDelayTest`)
|
||||
|
||||
Two tests, same shape, one difference in the URL. Without `DB_CLOSE_DELAY=-1`: create a table,
|
||||
insert a row, close the only open connection, reconnect with a fresh connection to the *same*
|
||||
URL --
|
||||
|
||||
```
|
||||
JdbcSQLSyntaxErrorException: Table "T" not found (this database is empty)
|
||||
```
|
||||
|
||||
H2 tore the entire in-memory database down the instant the last connection closed; the
|
||||
"reconnect" actually created a brand-new, empty database that happens to share a name. With
|
||||
`DB_CLOSE_DELAY=-1` on the same URL, the identical close-then-reconnect sequence sees the row
|
||||
that was inserted before the close. This is exactly why every entry in `TestDbSupport.Db`'s H2
|
||||
variants carries this flag, and why forgetting it produces intermittent, connection-timing-
|
||||
dependent test failures rather than a clean, consistent error.
|
||||
|
||||
## Startup time (indicative only -- shared sandbox container)
|
||||
|
||||
Three `SessionFactory` builds per engine, `System.nanoTime()`, in this specific shared sandbox
|
||||
([`docs/output/testdb-startup-timing.txt`](output/testdb-startup-timing.txt)):
|
||||
|
||||
```
|
||||
H2: 1628 ms, 83 ms, 62 ms
|
||||
HSQLDB: 238 ms, 79 ms, 74 ms
|
||||
DERBY: 637 ms, 176 ms, 125 ms
|
||||
```
|
||||
|
||||
The first run of whichever engine happens to go first pays a one-time JVM/driver class-loading
|
||||
cost (1.6s for H2 here) that has nothing to do with that database specifically -- note HSQLDB's
|
||||
first run, second in sequence, only cost 238ms. Steady-state, all three build a `SessionFactory`
|
||||
against an empty in-memory schema in well under 200ms. Treat the specific numbers as
|
||||
order-of-magnitude only; this container is shared and not isolated for benchmarking.
|
||||
|
||||
## Testcontainers: not runnable here, kept honest and short
|
||||
|
||||
Testcontainers 2.0.5 is the current GA and is where real cross-database parity testing belongs
|
||||
once H2/HSQLDB/Derby's dialect emulation gaps (MODE= not actually changing SQL dialect, Derby's
|
||||
now-separate community dialect, the CHAR-padding and reserved-word divergences documented above)
|
||||
matter enough to require the real database. **Docker was not available in this sandbox** (no
|
||||
`docker` binary, no `/var/run/docker.sock`), so nothing Testcontainers-based was attempted or
|
||||
run here -- this is stated plainly rather than faked. The recommendation, unchanged from
|
||||
standard practice: use the in-memory engines for fast unit-level ORM tests in the everyday CI
|
||||
loop, and Testcontainers for a slower, separate integration stage that exercises the real
|
||||
production database engine.
|
||||
|
||||
[← Previous: 08 — Stored procedures](08-stored-procedures.md) | [Next: 10 — Mocking JNDI datasources →](10-mocking-jndi-datasources.md)
|
||||
Executable
+171
@@ -0,0 +1,171 @@
|
||||
# 10 — Mocking JNDI DataSources, verified against Spring Framework 7.0.9 and simple-jndi 0.25.0
|
||||
|
||||
[← Previous: 09 — Testing with in-memory databases](09-testing-in-memory-databases.md) | [Next: 11 — Proxies and lazy initialization →](11-proxies-and-lazy-initialization.md)
|
||||
|
||||
Backs [ankurm.com: mocking JNDI datasources](https://ankurm.com/testing-hibernate-7-mocking-jndi-datasources-without-the-container/).
|
||||
|
||||
Companion code: [`src/test/java/com/ankurm/hibernatedemo/jndi/`](../src/test/java/com/ankurm/hibernatedemo/jndi/) (three test classes —
|
||||
[`JndiDataSourceResolutionTest`](../src/test/java/com/ankurm/hibernatedemo/jndi/JndiDataSourceResolutionTest.java),
|
||||
[`HibernateJndiDataSourceTest`](../src/test/java/com/ankurm/hibernatedemo/jndi/HibernateJndiDataSourceTest.java),
|
||||
[`CrossTestPollutionTest`](../src/test/java/com/ankurm/hibernatedemo/jndi/CrossTestPollutionTest.java) —
|
||||
seven tests, all green together in one run -- see [`docs/output/jndi-tests-run.txt`](output/jndi-tests-run.txt)
|
||||
(filtered) and [`docs/output/jndi-full-run.txt`](output/jndi-full-run.txt) (unfiltered Surefire capture of the same
|
||||
run). Environment: Hibernate ORM 7.4.5.Final, Spring Boot 4.1.1, Spring Framework 7.0.9, JDK 25,
|
||||
H2 2.4.240, simple-jndi 0.25.0 (`com.github.h-thurow:simple-jndi`, test scope).
|
||||
|
||||
## `SimpleNamingContextBuilder`: gone, and it's not a recent change
|
||||
|
||||
The article this replaces doesn't use `SimpleNamingContextBuilder`, but it's the most commonly
|
||||
recommended "just use Spring's mock JNDI" answer elsewhere, so it's worth settling with evidence.
|
||||
`unzip -l` against the actual jars ([`docs/output/jndi-simplenamingcontextbuilder-removal.txt`](output/jndi-simplenamingcontextbuilder-removal.txt)):
|
||||
|
||||
- `spring-test-5.3.31.jar` (last of the 5.x line): `org/springframework/mock/jndi/` present,
|
||||
8 class files including `SimpleNamingContextBuilder.class`.
|
||||
- `spring-test-6.0.0.jar`: zero matches for `naming` or `jndi` anywhere in the jar.
|
||||
- `spring-test-7.0.9.jar` (what this whole blog batch verifies against): same, zero matches.
|
||||
|
||||
So it went in Spring Framework 6.0.0 -- the same release that moved the whole framework from
|
||||
`javax.*` to `jakarta.*` for Jakarta EE 9. There is **no direct built-in replacement** in
|
||||
`spring-test` itself; the practical answer for the last several years has been a third-party
|
||||
library, which is exactly why this chapter exists. One nuance worth stating precisely: JNDI
|
||||
(`javax.naming.*`) is a **Java SE API** shipped in the `java.naming` module, not a Jakarta EE
|
||||
API, so it did not get renamed to `jakarta.naming` the way `javax.persistence` and
|
||||
`javax.servlet` did. simple-jndi's `MemoryContextFactory` still `implements
|
||||
javax.naming.spi.InitialContextFactory` in 2026, and always will unless the JDK itself changes
|
||||
it.
|
||||
|
||||
## Getting simple-jndi 0.25.0 actually working
|
||||
|
||||
First correction to the article's own dependency block: the artifact coordinates it used,
|
||||
`simple-jndi:simple-jndi:0.11.4.1`, are an old, essentially abandoned groupId. The maintained
|
||||
fork used throughout this blog batch is `com.github.h-thurow:simple-jndi:0.25.0`. Second: the
|
||||
article's `jndi.properties` sets `java.naming.provider.url=org.osjava.sj.memory
|
||||
.MemoryContextFactory` -- that package does not exist in the 0.25.0 jar at all
|
||||
([`docs/output/jndi-simplejndi-jar-listing.txt`](output/jndi-simplejndi-jar-listing.txt)). The real class is
|
||||
`org.osjava.sj.MemoryContextFactory`, and the property that should carry it is
|
||||
`java.naming.factory.initial`, not `java.naming.provider.url`.
|
||||
|
||||
A working bind-then-lookup, from `JndiDataSourceResolutionTest`:
|
||||
|
||||
```java
|
||||
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.osjava.sj.MemoryContextFactory");
|
||||
System.setProperty("org.osjava.sj.jndi.shared", "true"); // see below -- this one is easy to miss
|
||||
|
||||
Context ctx = new InitialContext();
|
||||
ctx.createSubcontext("java:"); ctx.createSubcontext("java:comp"); /* ...etc */
|
||||
ctx.bind(JNDI_NAME, dataSource);
|
||||
|
||||
DataSource looked = (DataSource) new InitialContext().lookup(JNDI_NAME);
|
||||
```
|
||||
|
||||
`org.osjava.sj.jndi.shared=true` is the detail every abbreviated example skips, and skipping it
|
||||
produces a confusing failure: without it, `javap -c` on `MemoryContextFactory.class`
|
||||
([`docs/output/proxy-settings-javap.txt`](output/proxy-settings-javap.txt)'s sibling investigation technique, applied here) shows
|
||||
the factory branches on that exact property name and, if it's not `"true"`, hands back a **brand
|
||||
new, empty** `MemoryContext` on every single `new InitialContext()` call instead of consulting
|
||||
its static, JVM-shared cache. A `bind()` through one `InitialContext` instance is then invisible
|
||||
to a `lookup()` through a different one -- even inside the same test method, if the code happens
|
||||
to construct more than one `InitialContext`. This was not a hypothetical: it's exactly the first
|
||||
failure this investigation hit.
|
||||
|
||||
Also demonstrated, and also driving Hibernate itself (not just a raw JDBC lookup): Hibernate's
|
||||
`hibernate.connection.datasource` setting (constant `DATASOURCE` in `org.hibernate.cfg
|
||||
.JdbcSettings`, confirmed via `javap`, [`docs/output/jndi-hibernate-datasource-setting-javap.txt`](output/jndi-hibernate-datasource-setting-javap.txt))
|
||||
resolves a JNDI name into a real, working `SessionFactory` --
|
||||
`HibernateJndiDataSourceTest` builds one and runs `SELECT 1` through it. Verbatim log line
|
||||
proving the resolution actually went through JNDI, not a URL:
|
||||
|
||||
```
|
||||
HHH10001005: Database info:
|
||||
DataSource JNDI name [jdbc/HibernateTestDS]
|
||||
Database JDBC URL [jdbc:h2:mem:hibernate-jndi-test]
|
||||
...
|
||||
Pool: DataSourceConnectionProvider
|
||||
```
|
||||
|
||||
## The failure modes, verbatim
|
||||
|
||||
`NoInitialContextException` when `java.naming.factory.initial` is never set:
|
||||
|
||||
```
|
||||
Need to specify class name in environment or system property, or in an application resource file: java.naming.factory.initial
|
||||
```
|
||||
|
||||
`NameNotFoundException` on an unbound name -- message is just the name itself:
|
||||
|
||||
```
|
||||
java:comp/env/jdbc/DoesNotExist
|
||||
```
|
||||
|
||||
`NameAlreadyBoundException` across two tests sharing a JVM -- reproduced on purpose in
|
||||
`CrossTestPollutionTest` (test A binds and never cleans up; test B tries to bind the same name):
|
||||
|
||||
```
|
||||
Name jdbc/SharedAcrossTests already bound. Use rebind() to override
|
||||
```
|
||||
|
||||
That message's own suggestion (`rebind()` instead of `bind()`) does make the immediate error go
|
||||
away, but it is a band-aid, not the fix -- it papers over test A's leak rather than closing it.
|
||||
`CrossTestPollutionTest`'s third test spells out the real fix: whatever a test binds, that same
|
||||
test unbinds in `@AfterEach`, unconditionally, so nothing survives to the next test class in the
|
||||
same JVM.
|
||||
|
||||
This surfaced for real, by accident, in this exact investigation: once all three JNDI test
|
||||
classes ran together in one Surefire invocation instead of one at a time, `HibernateJndiDataSourceTest`'s
|
||||
`@BeforeEach` started throwing `NameAlreadyBoundException` on `ctx.createSubcontext("jdbc")` --
|
||||
a *different* test class in the same run had already created that subcontext and never removed
|
||||
it. The fix applied ([`docs/output/jndi-tests-run.txt`](output/jndi-tests-run.txt) shows the resulting clean run) was to make
|
||||
subcontext creation idempotent (catch `NameAlreadyBoundException`, treat "already there" as
|
||||
success) in addition to unbinding leaf names in `@AfterEach`. Simple-JNDI's shared, static,
|
||||
JVM-wide namespace is not a toy problem confined to a contrived demo -- it is the normal
|
||||
behavior of the library, and it bit this test suite the first time the suite ran as a whole.
|
||||
|
||||
## Boot 4.1.1 specifics: `spring.datasource.jndi-name` is alive, relocated
|
||||
|
||||
`javap` against the actual 4.1.1 jars ([`docs/output/jndi-boot-autoconfig-javap.txt`](output/jndi-boot-autoconfig-javap.txt)) confirms
|
||||
both pieces still exist:
|
||||
|
||||
- `org.springframework.boot.jdbc.autoconfigure.JndiDataSourceAutoConfiguration` -- a real class,
|
||||
with a `dataSource(DataSourceProperties, ApplicationContext)` factory method.
|
||||
- `DataSourceProperties.jndiName` -- the field backing `spring.datasource.jndi-name`, with its
|
||||
getter/setter intact.
|
||||
|
||||
The relocation matters for anyone grepping for it in the wrong place: this is in the
|
||||
**`spring-boot-jdbc`** module, not `spring-boot-autoconfigure` -- `spring-boot-autoconfigure-4.1.1.jar`
|
||||
has zero matches for `jndi` at all. This is the same Boot 4 autoconfigure-module split noted
|
||||
elsewhere in this batch (JPA landed in `spring-boot-jpa`; JDBC/datasource landed in
|
||||
`spring-boot-jdbc`).
|
||||
|
||||
What did **not** get resolved in this sandbox: a full `@SpringBootTest` actually resolving
|
||||
`spring.datasource.jndi-name` end-to-end through Boot's own `JndiDataSourceAutoConfiguration`.
|
||||
Standalone simple-jndi bind/lookup worked perfectly (proven above, repeatedly, including through
|
||||
Spring's own `JndiTemplate` called directly). But inside a real `ApplicationContext` refresh,
|
||||
the `dataSource` bean's JNDI lookup consistently threw `NameNotFoundException` even though: the
|
||||
binding was moved to a static initializer (to run before `SpringExtension`'s `BeforeAllCallback`,
|
||||
which fires before a test class's own `@BeforeAll`); the class loading, `System.identityHashCode`,
|
||||
and classloader of `MemoryContextFactory` were confirmed identical between the successful
|
||||
standalone lookup and the failing in-context one via a diagnostic `BeanFactoryPostProcessor`; the
|
||||
relevant system properties (`java.naming.factory.initial`, `org.osjava.sj.jndi.shared`) were
|
||||
confirmed present and correct at the point of failure; and no `jndi.properties` resource or
|
||||
JNDI `InitialContextFactoryBuilder` registration was found anywhere on the 107-jar test
|
||||
classpath. The root cause was not found. `HibernateJndiDataSourceTest` (Hibernate's own
|
||||
`hibernate.connection.datasource`, no Spring autoconfiguration involved) is the test that
|
||||
carries the "Hibernate/Spring resolves it by name" claim for this chapter -- the
|
||||
Boot-autoconfiguration-specific path is documented as class-and-property-exist-but-live-wiring-unverified,
|
||||
not glossed over as working.
|
||||
|
||||
## Is mock JNDI still the right answer in 2026?
|
||||
|
||||
Being honest about what this investigation actually found: mock JNDI is a legacy technique kept
|
||||
alive for the shrinking set of applications that still get deployed into a real Java EE/Jakarta
|
||||
EE application server (WildFly, Payara) where a container-managed `DataSource` is genuinely the
|
||||
only path to a connection. For anything running as a Spring Boot fat jar -- the overwhelming
|
||||
majority of new work -- there is no container JNDI tree to fake in the first place, so mocking
|
||||
one in tests is solving a problem the production topology doesn't have. The honest recommendation
|
||||
for a Boot application in 2026 is what the rest of this repo already does (see
|
||||
[chapter 09](09-testing-in-memory-databases.md)): an in-memory database
|
||||
or Testcontainers wired through `spring.datasource.url`, not JNDI. Reach for simple-jndi
|
||||
specifically when the application under test really is deployed via JNDI in production and the
|
||||
test needs to mirror that lookup path -- not as a generic "how do I mock a DataSource" answer.
|
||||
|
||||
[← Previous: 09 — Testing with in-memory databases](09-testing-in-memory-databases.md) | [Next: 11 — Proxies and lazy initialization →](11-proxies-and-lazy-initialization.md)
|
||||
Executable
+197
@@ -0,0 +1,197 @@
|
||||
# 11 — Proxies and LazyInitializationException, verified against Hibernate 7.4.5.Final
|
||||
|
||||
[← Previous: 10 — Mocking JNDI datasources](10-mocking-jndi-datasources.md) | [Next: 12 — Association mappings →](12-association-mappings.md)
|
||||
|
||||
Backs [ankurm.com: proxies and the LazyInitializationException](https://ankurm.com/mastering-hibernate-7-proxies-and-the-lazyinitializationexception/).
|
||||
|
||||
Companion code: [`src/main/java/com/ankurm/hibernatedemo/proxy/`](../src/main/java/com/ankurm/hibernatedemo/proxy/) (entities —
|
||||
[`ProxyBook`](../src/main/java/com/ankurm/hibernatedemo/proxy/ProxyBook.java),
|
||||
[`ProxyPublisher`](../src/main/java/com/ankurm/hibernatedemo/proxy/ProxyPublisher.java),
|
||||
[`ProxyReview`](../src/main/java/com/ankurm/hibernatedemo/proxy/ProxyReview.java)) and
|
||||
[`src/test/java/com/ankurm/hibernatedemo/proxy/`](../src/test/java/com/ankurm/hibernatedemo/proxy/) (six test classes, twelve tests, all green).
|
||||
Raw output: `docs/output/proxy-*.txt`. Environment: Hibernate ORM 7.4.5.Final, Spring Boot
|
||||
4.1.1, Spring Framework 7.0.9, Jakarta Persistence 3.2.0, JDK 25 (Temurin), H2 2.4.240.
|
||||
|
||||
This chapter and [chapter 01](01-get-vs-load.md) are the same mechanism seen from two directions:
|
||||
01 measures what `get()` vs `getReference()` actually do to the persistence context and when a
|
||||
`SELECT` fires; this chapter measures what the *object* `getReference()` hands back actually is,
|
||||
and what breaks when it outlives its session. Read together, they cover the whole proxy
|
||||
lifecycle from creation to `LazyInitializationException`.
|
||||
|
||||
## What a proxy actually is, and the two ways to break naive code with it
|
||||
|
||||
`getReference()` does not hand you back an instance of your entity class. In 7.4.5.Final it
|
||||
hands you a **ByteBuddy-generated nested class named `$HibernateProxy`** —
|
||||
`com.ankurm.hibernatedemo.proxy.ProxyBook$HibernateProxy`, confirmed live in
|
||||
[`docs/output/proxy-lazy-init-and-identity.txt`](output/proxy-lazy-init-and-identity.txt). That is not the Javassist-era naming scheme
|
||||
(`EntityName_$$_javassist_N`) that still circulates in older blog posts and even in some current
|
||||
ones — Hibernate moved its default bytecode provider to ByteBuddy years ago, and 7.4.5 keeps the
|
||||
proxy as a literal static nested class of the entity itself, not a same-package sibling class.
|
||||
|
||||
Two things follow from that, and both are demonstrated in `ProxyIdentityTest`:
|
||||
|
||||
- `proxy instanceof ProxyBook` is `true` — the generated class extends your entity.
|
||||
- `proxy.getClass() == ProxyBook.class` is `false`. Any code that branches on `getClass()`
|
||||
instead of `instanceof`, or relies on the JPA-default `equals()`/`hashCode()` (object
|
||||
identity), silently breaks: a `HashSet<ProxyPublisher>` containing the real, managed instance
|
||||
does not recognize a proxy for the exact same row as a member (`proxyIdentityTest
|
||||
.naiveEqualsAndHashSet_cannotRecognizeProxyAndRealInstanceAsTheSameRow`, asserted, not
|
||||
claimed). Chapter 01's own proxy-identity experiment reaches the identical conclusion from the
|
||||
`get()`/`getReference()` side — see
|
||||
[`01 — get() vs getReference(), Proxy identity experiment`](01-get-vs-load.md#proxy-identity-experiment).
|
||||
|
||||
`Hibernate.getClass(proxy)` is the fix — it unwraps to the real entity class regardless of proxy
|
||||
state, and it's asserted to return `ProxyPublisher.class` even for an uninitialized reference.
|
||||
|
||||
## The exception, verbatim — and it is not one message, it's two
|
||||
|
||||
Every blog post on this topic (including the one this replaces) quotes a single wording for
|
||||
`LazyInitializationException`. Running it for real turns up **two different message templates**,
|
||||
depending on whether the frozen thing is a to-one association or a collection:
|
||||
|
||||
```
|
||||
# Collection (ProxyBook.reviews, a LAZY @OneToMany), accessed after session close:
|
||||
Cannot lazily initialize collection of role 'com.ankurm.hibernatedemo.proxy.ProxyBook.reviews' with key '1' (no session)
|
||||
|
||||
# To-one proxy (a getReference() result), accessed after session close:
|
||||
Could not initialize proxy [com.ankurm.hibernatedemo.proxy.ProxyBook#3] - no session
|
||||
```
|
||||
|
||||
Note the capitalization on the second one too: it's `Could` (capital) and `no session`
|
||||
(lower-case s) — not the commonly-quoted "could not initialize proxy ... no **S**ession". Both
|
||||
are `org.hibernate.LazyInitializationException` (verified: `ex.getClass().getName()` printed and
|
||||
asserted equal to that string), but if you're grepping logs for one exact phrase, you need both.
|
||||
See `LazyInitializationTest` for both reproductions and [`docs/output/proxy-lazy-init-and-identity.txt`](output/proxy-lazy-init-and-identity.txt)
|
||||
for the verbatim capture (also mirrored, unfiltered, in [`docs/output/proxy-lazy-and-identity-run.txt`](output/proxy-lazy-and-identity-run.txt)).
|
||||
|
||||
## `Hibernate.initialize()` / `isInitialized()` / `unproxy()` — confirmed against the 7.4.5 jar
|
||||
|
||||
`javap` against `hibernate-core-7.4.5.Final.jar` (full output in
|
||||
[`docs/output/proxy-settings-javap.txt`](output/proxy-settings-javap.txt)) shows the signatures actually shipped:
|
||||
|
||||
```
|
||||
public static void initialize(java.lang.Object) throws org.hibernate.HibernateException;
|
||||
public static boolean isInitialized(java.lang.Object);
|
||||
public static java.lang.Object unproxy(java.lang.Object);
|
||||
public static <T> T unproxy(T, java.lang.Class<T>);
|
||||
```
|
||||
|
||||
`unproxy()` has **two** overloads, not one — a no-cast version that returns `Object`, and a
|
||||
typed version that takes the target `Class<T>` and returns `T` directly. Both are exercised in
|
||||
`LazyInitializationTest.hibernateUnproxy_...`. A side effect worth knowing: calling
|
||||
`Hibernate.unproxy()` on an uninitialized proxy *initializes it* — `isInitialized()` flips from
|
||||
`false` to `true` as a consequence, not just as a precondition.
|
||||
|
||||
## fetchgraph vs. loadgraph, demonstrated, not just stated
|
||||
|
||||
Every article states the rule ("loadgraph keeps defaults for what's not named; fetchgraph forces
|
||||
everything not named to LAZY") and almost none show it happening. `EntityGraphFetchTest` builds
|
||||
one entity (`ProxyBook`) with two associations of different default fetch types — `publisher`
|
||||
(`@ManyToOne`, default EAGER) and `reviews` (`@OneToMany`, explicit LAZY) — and one named graph
|
||||
that mentions only `reviews`:
|
||||
|
||||
| Hint | SQL joins | `publisher` after fetch | `reviews` after fetch |
|
||||
|---|---|---|---|
|
||||
| none (plain `find()`) | `left join proxy_publisher` only | initialized (mapped EAGER) | **not** initialized (mapped LAZY) |
|
||||
| `jakarta.persistence.loadgraph` | `left join proxy_publisher` **and** `left join proxy_review` | initialized | initialized |
|
||||
| `jakarta.persistence.fetchgraph` | `left join proxy_review` **only** | **not initialized** (forced to LAZY, despite EAGER mapping) | initialized |
|
||||
|
||||
The middle column is the whole point: with `fetchgraph`, `book.getPublisher()` comes back as a
|
||||
`ProxyPublisher$HibernateProxy` even though the mapping says EAGER, because fetchgraph treats
|
||||
the graph as the *entire* fetch plan rather than an addition to the mapping's defaults. Verbatim
|
||||
SQL for all three shapes is in [`docs/output/proxy-entitygraph-fetch-vs-load.txt`](output/proxy-entitygraph-fetch-vs-load.txt) (raw run in
|
||||
[`docs/output/proxy-entitygraph-run.txt`](output/proxy-entitygraph-run.txt)). Chapter 12 covers the collection-side counterpart of this same
|
||||
lazy/eager boundary — N+1 counting and `@BatchSize` — see
|
||||
[`12 — Association mappings`](12-association-mappings.md#counting-the-n1).
|
||||
|
||||
## `hibernate.enable_lazy_load_no_trans`: still there, still works, now flagged `@Unsafe`
|
||||
|
||||
This setting has a reputation for being on its way out. It is not gone in 7.4.5.Final —
|
||||
`org.hibernate.cfg.TransactionSettings.ENABLE_LAZY_LOAD_NO_TRANS` still resolves to the string
|
||||
`hibernate.enable_lazy_load_no_trans` (confirmed by `javap`, see
|
||||
[`docs/output/proxy-settings-javap.txt`](output/proxy-settings-javap.txt)). What *is* new-ish and worth a headline: the constant now
|
||||
carries a `@org.hibernate.cfg.Unsafe` marker annotation — an empty marker interface Hibernate's
|
||||
own source uses to flag settings it does not want you reaching for, without actually removing
|
||||
them. `OpenInViewAndLazyLoadNoTransTest` turns it on
|
||||
(`spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true`) and confirms it functionally
|
||||
does what it always did: a to-one proxy, accessed after its originating session and transaction
|
||||
have both closed, initializes successfully instead of throwing — Hibernate opens a temporary
|
||||
session behind the scenes to service exactly that one access. The `@Unsafe` label is
|
||||
Hibernate's own commentary on why you generally shouldn't reach for this, not a sign it's been
|
||||
deprecated or removed.
|
||||
|
||||
## OSIV: the default, its warning, and what it actually masks
|
||||
|
||||
`spring.jpa.open-in-view` defaults to `true` when left unset, and Boot prints a warning at
|
||||
startup that says exactly that — verified verbatim (not paraphrased) against
|
||||
`org.springframework.boot.jpa.autoconfigure.JpaBaseConfiguration$JpaWebConfiguration`'s
|
||||
bytecode:
|
||||
|
||||
```
|
||||
spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed
|
||||
during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
|
||||
```
|
||||
|
||||
(Note the package: `org.springframework.boot.jpa.autoconfigure`, not `org.springframework.boot
|
||||
.autoconfigure.orm.jpa` — Boot 4 split its autoconfigure module and JPA's auto-configuration now
|
||||
lives in the separate `spring-boot-jpa` artifact.)
|
||||
|
||||
Proving the *masking* claim required a real HTTP request — OSIV is implemented by
|
||||
`OpenEntityManagerInViewInterceptor`, which only exists for actual servlet requests, so
|
||||
`OsivDefaultWarningTest` and `OsivDisabledExceptionTest` spin up a real embedded Tomcat
|
||||
(`@SpringBootTest(webEnvironment = RANDOM_PORT)`) with one controller
|
||||
([`OsivBookController`](../src/test/java/com/ankurm/hibernatedemo/proxy/OsivBookController.java)/[`OsivBookService`](../src/test/java/com/ankurm/hibernatedemo/proxy/OsivBookService.java)) that returns a `ProxyBook` entity directly and lets
|
||||
Jackson serialize `getReviews()` on the response-writing thread — deliberately not a DTO,
|
||||
because the DTO is the fix, and the point here is what happens without it. Same code, same
|
||||
data, only the property differs:
|
||||
|
||||
```
|
||||
# open-in-view left unset (Boot default true): GET /osiv/books/1
|
||||
200 {"title":"OSIV Default Book","publisher":{...},"id":1,"reviews":[{"comment":"Rendered fine","id":1}]}
|
||||
|
||||
# open-in-view=false: GET /osiv/books/2 (identical entity graph, identical controller)
|
||||
500 {"timestamp":"...","status":500,"error":"Internal Server Error","path":"/osiv/books/2"}
|
||||
```
|
||||
|
||||
Server-side log for the second case (captured via `CapturedOutput`, not inferred):
|
||||
|
||||
```
|
||||
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write
|
||||
JSON: Cannot lazily initialize collection of role 'com.ankurm.hibernatedemo.proxy.ProxyBook.reviews'
|
||||
with key '2' (no session)]
|
||||
```
|
||||
|
||||
Worth calling out as its own gotcha: the HTTP error *body* Boot's default `BasicErrorController`
|
||||
returns is a bare `{"timestamp":...,"status":500,...}` even with
|
||||
`server.error.include-message=always` set — the failure happens inside the Jackson
|
||||
`HttpMessageConverter` while writing the response, which Boot reports as a generic 500 rather
|
||||
than routing the original exception's message into the error attributes map. If you only look at
|
||||
the HTTP response, you will not learn why it failed; you have to check the application log,
|
||||
which is exactly what real incident response looks like for this failure mode. Full sequence in
|
||||
[`docs/output/proxy-osiv-and-no-trans.txt`](output/proxy-osiv-and-no-trans.txt) (raw run in [`docs/output/proxy-osiv-run.txt`](output/proxy-osiv-run.txt)).
|
||||
|
||||
## Bytecode enhancement (`hibernate-enhance-maven-plugin`) — not run here
|
||||
|
||||
The article draft this replaces implies bytecode enhancement changes proxy behavior in ways
|
||||
worth demonstrating. Two settings for it are real and confirmed present in 7.4.5.Final —
|
||||
`org.hibernate.cfg.BytecodeSettings.ENHANCER_ENABLE_LAZY_INITIALIZATION`,
|
||||
`ENHANCER_ENABLE_DIRTY_TRACKING`, and `ENHANCER_ENABLE_ASSOCIATION_MANAGEMENT` all exist
|
||||
([`docs/output/proxy-settings-javap.txt`](output/proxy-settings-javap.txt)). Wiring up the actual Maven plugin to enhance classes at
|
||||
build time and diff the resulting behavior was not attempted: a quick check for
|
||||
`org.hibernate.orm.tooling:hibernate-enhance-maven-plugin:7.4.5.Final` and
|
||||
`org.hibernate.orm:hibernate-enhance-maven-plugin:7.4.5.Final` on Maven Central both came back
|
||||
"could not be resolved" in this sandbox. Per the brief's own guidance, this looked like a rabbit
|
||||
hole rather than a quick add — flagging it honestly rather than guessing at what enhancement
|
||||
would do differently here.
|
||||
|
||||
## Testcontainers, Docker, and the honest gap
|
||||
|
||||
Not applicable to this chapter directly (see [chapter 09](09-testing-in-memory-databases.md) for
|
||||
that), but it's worth noting here too: everything above ran against a single shared H2
|
||||
in-memory database in a sandboxed container. No Docker was available, so nothing here was
|
||||
cross-checked against a real Postgres/MySQL proxy-and-lazy-loading story — the
|
||||
LazyInitializationException and proxy identity mechanics are Hibernate-internal and
|
||||
database-agnostic, but that claim itself rests on understanding of Hibernate's architecture
|
||||
rather than an executed cross-database test.
|
||||
|
||||
[← Previous: 10 — Mocking JNDI datasources](10-mocking-jndi-datasources.md) | [Next: 12 — Association mappings →](12-association-mappings.md)
|
||||
Executable
+171
@@ -0,0 +1,171 @@
|
||||
# 12 — Association mappings: what the numbers actually say
|
||||
|
||||
[← Previous: 11 — Proxies and lazy initialization](11-proxies-and-lazy-initialization.md) | [Next: 13 — Date and time mapping →](13-date-and-time-mapping.md)
|
||||
|
||||
Backs [ankurm.com: Hibernate 7 association mappings](https://ankurm.com/master-hibernate-7-association-mappings-the-ultimate-guide-for-high-performance-java-apps/).
|
||||
|
||||
Every claim below was produced by a JUnit test in [`src/test/java/com/ankurm/hibernatedemo/association/`](../src/test/java/com/ankurm/hibernatedemo/association/),
|
||||
run against Hibernate 7.4.5.Final / H2 2.4.240, with `hibernate.generate_statistics=true` and
|
||||
`Statistics.getPrepareStatementCount()` as the counter. Nothing here is asserted from memory --
|
||||
every number has a test that fails if the number changes. Chapter 11 covers the same lazy vs.
|
||||
eager boundary from the to-one/proxy side (`LazyInitializationException`, `fetchgraph` vs.
|
||||
`loadgraph`) -- see [`11 — Proxies and lazy initialization`](11-proxies-and-lazy-initialization.md);
|
||||
this chapter is the collection side of that same story.
|
||||
|
||||
## Counting the N+1
|
||||
|
||||
Seed: 100 authors, 3 books each. [`NPlusOneTest`](../src/test/java/com/ankurm/hibernatedemo/association/NPlusOneTest.java) measures four strategies against the identical
|
||||
data:
|
||||
|
||||
| Strategy | Query count | Test |
|
||||
|---|---|---|
|
||||
| Naive lazy iteration (`author.getBooks().size()` in a loop) | **101** | `naiveLazyIteration_firesOneQueryPerAuthor_theClassicNPlusOne` |
|
||||
| JPQL `JOIN FETCH` | **1** | `jpqlFetchJoin_firesExactlyOneQuery` |
|
||||
| `@EntityGraph` (`jakarta.persistence.fetchgraph` hint) | **1** | `entityGraph_firesExactlyOneQuery` |
|
||||
| `@BatchSize(size = 10)` | **11** | `batchSize10_collapsesNPlusOneIntoCeilNOverBatchSizePlusOne` |
|
||||
|
||||
The batch-size math is worth spelling out: with 100 authors and a batch size of 10, Hibernate
|
||||
issues `ceil(100 / 10) = 10` batched `IN (...)` selects for the collections, plus the 1 select
|
||||
for the authors themselves -- `11` total, exactly matching `ceil(N / batchSize) + 1`. This is not
|
||||
an approximation; `BatchSizeSweepTest`-style math generalizes: doubling `batchSize` to 20 would
|
||||
give `ceil(100/20)+1 = 6`.
|
||||
|
||||
Raw output: [`docs/output/association-n-plus-one.txt`](output/association-n-plus-one.txt).
|
||||
|
||||
## MultipleBagFetchException
|
||||
|
||||
[`BagAuthorList`](../src/main/java/com/ankurm/hibernatedemo/association/BagAuthorList.java) has two `List` (bag-semantics) collections: `books` and `awards`. Fetch-joining
|
||||
both in one JPQL query --
|
||||
|
||||
```java
|
||||
SELECT a FROM BagAuthorList a JOIN FETCH a.books JOIN FETCH a.awards
|
||||
```
|
||||
|
||||
-- throws. The **verbatim** exception, captured from a real run:
|
||||
|
||||
```
|
||||
wrapper class: java.lang.IllegalArgumentException
|
||||
root cause class: org.hibernate.loader.MultipleBagFetchException
|
||||
message: cannot simultaneously fetch multiple bags: [com.ankurm.hibernatedemo.association.BagAuthorList.awards, com.ankurm.hibernatedemo.association.BagAuthorList.books]
|
||||
```
|
||||
|
||||
**Correction worth flagging**: `EntityManager.createQuery(...).getResultList()` wraps this as
|
||||
`java.lang.IllegalArgumentException`, not `jakarta.persistence.PersistenceException`. If your
|
||||
code catches `PersistenceException` expecting to handle Hibernate query failures uniformly, this
|
||||
one slips past it.
|
||||
|
||||
Two fixes, both measured, in [`BagFetchTest`](../src/test/java/com/ankurm/hibernatedemo/association/BagFetchTest.java):
|
||||
|
||||
- **Fix 1 -- use `Set` instead of `List`.** [`BagAuthorSet`](../src/main/java/com/ankurm/hibernatedemo/association/BagAuthorSet.java) (identical shape, `Set` collections)
|
||||
runs the same double-fetch-join query with **zero** exceptions and **1** query total.
|
||||
- **Fix 2 -- two separate queries**, one `JOIN FETCH` each. **2** queries total, no exception,
|
||||
same data assembled in the application.
|
||||
|
||||
Raw output: [`docs/output/association-multiplebag-and-cartesian.txt`](output/association-multiplebag-and-cartesian.txt).
|
||||
|
||||
## The cartesian-product trap
|
||||
|
||||
Fetch-joining two collections that *are* allowed (both `Set`s) does not throw, but it does not
|
||||
avoid the underlying join math either. With 1 author, 4 books, 3 awards, fetch-joining both
|
||||
collections in one query:
|
||||
|
||||
- Raw SQL join row count: **12** (4 x 3 -- one row per (book, award) pair).
|
||||
- Entities returned to the application (via `SELECT DISTINCT` + Hibernate's root-entity
|
||||
de-duplication): **1**, fully populated with all 4 books and all 3 awards.
|
||||
|
||||
The row count explosion is real and happens at the database and JDBC layer regardless of how
|
||||
many entities eventually come back -- for large collections this is where "the query is fast in
|
||||
isolation but the app is slow" reports come from.
|
||||
|
||||
## The `@OneToOne` lazy trap
|
||||
|
||||
[`LazyUser`](../src/main/java/com/ankurm/hibernatedemo/association/LazyUser.java)`.profile` is the non-owning (`mappedBy`) side of an optional `@OneToOne`, declared
|
||||
`FetchType.LAZY`. Without bytecode enhancement, Hibernate cannot build a lazy proxy for it -- it
|
||||
has no foreign key of its own to defer against, so it cannot know whether a [`LazyProfile`](../src/main/java/com/ankurm/hibernatedemo/association/LazyProfile.java) row exists
|
||||
without querying. Measured in [`OneToOneLazyTest`](../src/test/java/com/ankurm/hibernatedemo/association/OneToOneLazyTest.java):
|
||||
|
||||
```
|
||||
LazyUser.find(): 2 queries fired BEFORE touching getProfile() at all
|
||||
after touching getProfile(): 2 queries total (no further query needed -- it already ran eagerly)
|
||||
```
|
||||
|
||||
The annotation says `LAZY`; the runtime behavior is eager. This is the trap.
|
||||
|
||||
The fix is not `@MapsId` alone -- it's removing the inverse mapping and querying by the shared
|
||||
primary key on demand:
|
||||
|
||||
```
|
||||
MiUser.find() (no mappedBy field at all): 1 query
|
||||
explicit MiProfile.find() by shared PK when actually needed: 2 total queries
|
||||
```
|
||||
|
||||
Loading the user alone costs exactly 1 query; [`MiProfile`](../src/main/java/com/ankurm/hibernatedemo/association/MiProfile.java) is fetched only when the code actually
|
||||
asks for it, using the same primary key value (`@MapsId`), via [`MiUser`](../src/main/java/com/ankurm/hibernatedemo/association/MiUser.java).
|
||||
|
||||
Raw output: [`docs/output/association-onetoone-lazy-trap.txt`](output/association-onetoone-lazy-trap.txt).
|
||||
|
||||
## Cascade and orphanRemoval
|
||||
|
||||
Two real behaviors, tested separately in [`CascadeOrphanTest`](../src/test/java/com/ankurm/hibernatedemo/association/CascadeOrphanTest.java) against [`CascadeAuthor`](../src/main/java/com/ankurm/hibernatedemo/association/CascadeAuthor.java)/[`CascadeBook`](../src/main/java/com/ankurm/hibernatedemo/association/CascadeBook.java) --
|
||||
and one of them is a correction of the common claim.
|
||||
|
||||
**Correction**: the frequently repeated claim is "assigning a new collection to an
|
||||
`orphanRemoval=true` field silently deletes the old rows." That's not what happens.
|
||||
`CascadeOrphanTest.cascadeAllPlusOrphanRemoval_reassigningTheCollectionThrowsInsteadOfSilentlyDeleting`
|
||||
shows Hibernate detects the dereferenced managed collection and throws at commit time:
|
||||
|
||||
```
|
||||
jakarta.persistence.RollbackException: Error while committing the transaction
|
||||
[A collection with orphan deletion was no longer referenced by the owning entity instance:
|
||||
com.ankurm.hibernatedemo.association.CascadeAuthor.books]
|
||||
root cause: org.hibernate.HibernateException
|
||||
```
|
||||
|
||||
The scenario that *does* silently delete is mutating the **same** managed collection instance in
|
||||
place -- e.g. `managed.getBooks().removeIf(...)`, the realistic pattern that reaches production.
|
||||
That test shows books going from 3 to 1 with no exception:
|
||||
|
||||
```
|
||||
cascade=ALL + orphanRemoval=true, in-place removeIf(): books before=3, books after=1
|
||||
```
|
||||
|
||||
**No `orphanRemoval`**: removing a child from the collection and flushing does nothing to the
|
||||
row -- no DELETE, no FK update. The row and its FK are untouched:
|
||||
|
||||
```
|
||||
orphanRemoval=false: after removing book2 from author.books and flushing,
|
||||
book2 row still exists = true, author_id still = 1
|
||||
```
|
||||
|
||||
Raw output: [`docs/output/association-cascade-orphan.txt`](output/association-cascade-orphan.txt).
|
||||
|
||||
## The owning side
|
||||
|
||||
Mutating only the inverse (`mappedBy`) side of a bidirectional association -- adding a book to
|
||||
`author.getBooks()` without ever calling `book.setAuthor(author)` -- never persists anything.
|
||||
The owning side (the entity holding the `@JoinColumn`) is the only thing Hibernate looks at when
|
||||
deciding what to write:
|
||||
|
||||
```
|
||||
owning side test: mutated only author2.getBooks().add(book) (inverse side),
|
||||
book.author after flush = null (FK not written)
|
||||
```
|
||||
|
||||
Raw output: [`docs/output/association-cascade-orphan.txt`](output/association-cascade-orphan.txt).
|
||||
|
||||
## Summary
|
||||
|
||||
| Claim | Verified value |
|
||||
|---|---|
|
||||
| Naive N+1 for 100 authors | 101 queries |
|
||||
| Fetch join / entity graph | 1 query |
|
||||
| `@BatchSize(10)` for 100 authors | 11 queries (`ceil(100/10)+1`) |
|
||||
| `MultipleBagFetchException` wrapper | `IllegalArgumentException`, not `PersistenceException` |
|
||||
| Cartesian join (4x3) | 12 SQL rows -> 1 deduplicated entity |
|
||||
| `mappedBy @OneToOne(LAZY)` | Still 2 queries -- eager despite the annotation |
|
||||
| `@MapsId` + no inverse field | 1 query for the parent; profile fetched only on demand |
|
||||
| Reassigning an orphanRemoval collection | Throws `HibernateException`, does not silently delete |
|
||||
| In-place mutation of an orphanRemoval collection | Does silently delete |
|
||||
| Inverse-side-only mutation | FK never written |
|
||||
|
||||
[← Previous: 11 — Proxies and lazy initialization](11-proxies-and-lazy-initialization.md) | [Next: 13 — Date and time mapping →](13-date-and-time-mapping.md)
|
||||
Executable
+204
@@ -0,0 +1,204 @@
|
||||
# 13 — Date and time mapping: what actually round-trips
|
||||
|
||||
[← Previous: 12 — Association mappings](12-association-mappings.md) | [Next: 14 — Named queries →](14-named-queries.md)
|
||||
|
||||
Backs [ankurm.com: Hibernate 7 date/time mapping](https://ankurm.com/mastering-hibernate-7-date-time-mapping-java-time-timezones-and-jdbc-4-2/).
|
||||
|
||||
Everything below comes from a JUnit test in [`src/test/java/com/ankurm/hibernatedemo/datetime/`](../src/test/java/com/ankurm/hibernatedemo/datetime/)
|
||||
against Hibernate 7.4.5.Final, run on H2 2.4.240 (and HSQLDB 2.7.3 where noted), Java 25. The
|
||||
sandbox JVM's own default time zone during these runs was `Asia/Calcutta` (+05:30) unless a test
|
||||
explicitly overrides `-Duser.timezone`.
|
||||
|
||||
## Basic temporal types round trip
|
||||
|
||||
[`TemporalTypesEntity`](../src/main/java/com/ankurm/hibernatedemo/datetime/TemporalTypesEntity.java) maps every basic temporal type in one entity. Generated DDL
|
||||
([`BasicTemporalTypesTest`](../src/test/java/com/ankurm/hibernatedemo/datetime/BasicTemporalTypesTest.java), H2 2.4.240):
|
||||
|
||||
```
|
||||
create table temporal_types (
|
||||
id bigint generated by default as identity,
|
||||
instant timestamp(6) with time zone,
|
||||
legacy_calendar timestamp(6),
|
||||
legacy_date_as_date date,
|
||||
legacy_date_as_timestamp timestamp(6),
|
||||
legacy_date_no_temporal timestamp(6),
|
||||
local_date date,
|
||||
local_date_time timestamp(6),
|
||||
local_time time(0),
|
||||
offset_date_time timestamp(6) with time zone,
|
||||
zoned_date_time timestamp(6) with time zone,
|
||||
primary key (id)
|
||||
)
|
||||
```
|
||||
|
||||
Round trip of every value came back correct ([`docs/output/datetime-basic-types.txt`](output/datetime-basic-types.txt)). One
|
||||
finding worth flagging: `legacyDateNoTemporal` is a `java.util.Date` field with **no**
|
||||
`@Temporal` annotation at all. It did not fail to bootstrap and did not throw -- Hibernate 7.4.5
|
||||
defaulted it to a `TIMESTAMP` column and round-tripped it correctly. The old JPA-provider
|
||||
requirement that `@Temporal` is mandatory on `Date`/`Calendar` fields does not hold here.
|
||||
|
||||
## `@Temporal` verified deprecated, and verified harmless when misapplied
|
||||
|
||||
```
|
||||
$ javap -v jakarta.persistence.Temporal # from jakarta.persistence-api-3.2.0.jar
|
||||
Deprecated: true
|
||||
RuntimeVisibleAnnotations:
|
||||
java.lang.Deprecated(since="3.2")
|
||||
```
|
||||
|
||||
`@Temporal` is formally deprecated since Jakarta Persistence 3.2 -- confirmed by bytecode
|
||||
inspection, not the javadoc prose. Chapter 05 confirms the identical boot-time warning on a
|
||||
`LocalDate` field; this chapter's [`TemporalOnJavaTimeEntity`](../src/main/java/com/ankurm/hibernatedemo/datetime/TemporalOnJavaTimeEntity.java) puts it on an `Instant` field instead
|
||||
-- see [`05 — JPA persistence annotations`](05-jpa-persistence-annotations.md#temporal-is-formally-deprecatedsince--32--and-it-is-a-silent-no-op-not-silent-silent)
|
||||
for the `LocalDate` case.
|
||||
|
||||
Using it anyway on `java.time` fields (`java.util.Date`/`Calendar` are its only legal targets)
|
||||
does not break anything in Hibernate 7.4.5. [`TemporalAnnotationTest`](../src/test/java/com/ankurm/hibernatedemo/datetime/TemporalAnnotationTest.java) puts
|
||||
`@Temporal(TemporalType.TIMESTAMP)` on an `Instant` field: the application context boots, and the
|
||||
value round-trips exactly. The framework logs a deprecation warning at boot
|
||||
(`HHH90000033: Encountered use of deprecated annotation ... at ...instantWithTemporalAnnotation`)
|
||||
but does not reject it. See [`docs/output/datetime-temporal-annotation.txt`](output/datetime-temporal-annotation.txt).
|
||||
|
||||
## The central experiment: `@TimeZoneStorage`
|
||||
|
||||
```
|
||||
$ javap org.hibernate.annotations.TimeZoneStorageType # hibernate-core-7.4.5.Final.jar
|
||||
NATIVE, NORMALIZE, NORMALIZE_UTC, COLUMN, AUTO, DEFAULT
|
||||
```
|
||||
|
||||
Six constants, not five -- `DEFAULT` is a real enum member (a sentinel meaning "consult
|
||||
`hibernate.timezone.default_storage`"), separate from the five storage strategies.
|
||||
|
||||
**What "default" resolves to.** `hibernate.timezone.default_storage` (confirmed present as
|
||||
`org.hibernate.cfg.MappingSettings.TIMEZONE_DEFAULT_STORAGE`) defaults, when unset, to
|
||||
`TimeZoneStorageType.DEFAULT` itself -- a second layer of indirection resolved by
|
||||
`MetadataBuildingOptions.getDefaultTimeZoneStorage()`, which asks the current SQL **Dialect**
|
||||
for its `TimeZoneSupport` and converts that into a storage strategy (confirmed by
|
||||
decompiling `MetadataBuilderImpl` and `TimeZoneStorageHelper` in hibernate-core 7.4.5.Final --
|
||||
not from a blog post). In practice, on H2 (which has native `TIMESTAMP WITH TIME ZONE` support),
|
||||
a column with **no** `@TimeZoneStorage` annotation at all ([`TimeZoneStorageEntity`](../src/main/java/com/ankurm/hibernatedemo/datetime/TimeZoneStorageEntity.java)) behaved identically to `NATIVE` in
|
||||
every test below, per [`TimeZoneStorageTest`](../src/test/java/com/ankurm/hibernatedemo/datetime/TimeZoneStorageTest.java).
|
||||
|
||||
**Storing `+05:30` and reading it back**, under the JVM's own default zone (`Asia/Calcutta`,
|
||||
itself `+05:30` -- chosen deliberately as a first baseline where the JVM zone matches the data):
|
||||
|
||||
```
|
||||
TZ_MODE no-annotation (default) = 2026-06-15T14:00+05:30
|
||||
TZ_MODE NATIVE = 2026-06-15T14:00+05:30
|
||||
TZ_MODE NORMALIZE = 2026-06-15T14:00+05:30
|
||||
TZ_MODE NORMALIZE_UTC = 2026-06-15T08:30Z
|
||||
TZ_MODE COLUMN = 2026-06-15T14:00+05:30
|
||||
TZ_MODE AUTO = 2026-06-15T14:00+05:30
|
||||
```
|
||||
|
||||
That alone doesn't show much -- `NORMALIZE` had nothing to normalize *to* since the JVM zone
|
||||
already matched. Rerunning the identical test with `-Duser.timezone=America/New_York` (JVM
|
||||
default zone changed, database untouched) is where the real behavior shows up:
|
||||
|
||||
```
|
||||
TZ_MODE no-annotation (default) = 2026-06-15T14:00+05:30 <- unchanged
|
||||
TZ_MODE NATIVE = 2026-06-15T14:00+05:30 <- unchanged
|
||||
TZ_MODE NORMALIZE = 2026-06-15T04:30-04:00 <- CHANGED: re-expressed in JVM's zone
|
||||
TZ_MODE NORMALIZE_UTC = 2026-06-15T08:30Z <- unchanged (always UTC)
|
||||
TZ_MODE COLUMN = 2026-06-15T14:00+05:30 <- unchanged
|
||||
TZ_MODE AUTO = 2026-06-15T14:00+05:30 <- unchanged
|
||||
```
|
||||
|
||||
Both readings represent the exact same instant (`2026-06-15T08:30:00Z`); only the *displayed*
|
||||
offset for `NORMALIZE` moved, because `NORMALIZE` explicitly re-expresses the stored value in
|
||||
whatever the JVM's current default zone is at read time. Every other mode is immune to a change
|
||||
in the JVM's default time zone -- **this is the JVM-default-timezone hazard, made concrete**: if
|
||||
your fleet ever runs with inconsistent `user.timezone` settings (a classic container migration
|
||||
issue), `NORMALIZE` is the one mode that will show you a different offset for identical data
|
||||
depending on which box read it. `NATIVE`, `COLUMN`, `AUTO`, and Hibernate's default all store and
|
||||
return the exact offset supplied, immune to the reading JVM's zone.
|
||||
|
||||
**`COLUMN` mode's DDL** does add a second column, exactly as advertised:
|
||||
|
||||
```
|
||||
create table tz_storage (
|
||||
...
|
||||
column_mode_col timestamp(6) with time zone,
|
||||
column_mode_col_tz integer,
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
(On HSQLDB, which lacks a native `WITH TIME ZONE` timestamp type for every mode, `AUTO` also
|
||||
picks up a companion `_tz integer` column -- confirming `AUTO`'s behavior is dialect-dependent,
|
||||
consistent with the `TimeZoneSupport`-driven resolution above.)
|
||||
|
||||
Raw output: [`docs/output/datetime-timezone-storage-default-jvm.txt`](output/datetime-timezone-storage-default-jvm.txt),
|
||||
[`docs/output/datetime-timezone-storage-nydefault.txt`](output/datetime-timezone-storage-nydefault.txt).
|
||||
|
||||
## Second-precision / truncation
|
||||
|
||||
Stored `LocalDateTime`/`Instant` ([`NanoPrecisionEntity`](../src/main/java/com/ankurm/hibernatedemo/datetime/NanoPrecisionEntity.java)) with `123456789` ns and read back, via
|
||||
[`NanosecondTruncationTest`](../src/test/java/com/ankurm/hibernatedemo/datetime/NanosecondTruncationTest.java) (H2) and [`NanosecondTruncationHsqldbTest`](../src/test/java/com/ankurm/hibernatedemo/datetime/NanosecondTruncationHsqldbTest.java) (HSQLDB):
|
||||
|
||||
| Database | Nanos in | Nanos out | Behavior |
|
||||
|---|---|---|---|
|
||||
| H2 2.4.240 | 123456789 | **123457000** | Rounds to microsecond precision |
|
||||
| HSQLDB 2.7.3 | 123456789 | **123456000** | Truncates to microsecond precision |
|
||||
|
||||
Same input, two different databases, two different results -- H2 rounds the last three digits
|
||||
away, HSQLDB drops them. Neither preserves true nanosecond precision (both cap at `timestamp(6)`,
|
||||
i.e. microseconds), but "rounds" vs "truncates" is a real, silent, database-specific behavior
|
||||
difference that can shift a stored value by up to half a microsecond depending on which engine is
|
||||
under the app.
|
||||
|
||||
**Correction**: `@Column(precision = 9)` on the temporal field had **zero effect** on the
|
||||
generated DDL or the stored precision in this experiment -- the column type stayed
|
||||
`timestamp(6)` regardless, on both databases. JPA's `precision`/`scale` `@Column` attributes are
|
||||
defined for **numeric** (`DECIMAL`) columns; they do not control fractional-second digits on a
|
||||
temporal column in Hibernate 7.4.5. A common piece of blog advice ("use
|
||||
`@Column(precision = 6)` to force microsecond storage") does not do anything here -- the
|
||||
precision was already fixed at 6 by the dialect's default temporal column type, with or without
|
||||
the annotation.
|
||||
|
||||
Raw output: [`docs/output/datetime-nanosecond-h2.txt`](output/datetime-nanosecond-h2.txt), [`docs/output/datetime-nanosecond-hsqldb.txt`](output/datetime-nanosecond-hsqldb.txt).
|
||||
|
||||
## `hibernate.jdbc.time_zone`
|
||||
|
||||
Confirmed to exist as `org.hibernate.cfg.JdbcSettings.JDBC_TIME_ZONE`. Setting it to
|
||||
`America/New_York` (JVM default left at `Asia/Calcutta`) and inspecting the **raw** stored value
|
||||
via a native `CAST(... AS VARCHAR)` query, in [`JdbcTimeZoneTest`](../src/test/java/com/ankurm/hibernatedemo/datetime/JdbcTimeZoneTest.java):
|
||||
|
||||
```
|
||||
original LocalDateTime = 2026-07-04T09:00
|
||||
raw DB value for LocalDateTime column = 2026-07-03 23:30:00 <- shifted!
|
||||
round-tripped LocalDateTime = 2026-07-04T09:00 <- but reads back correctly
|
||||
|
||||
original OffsetDateTime (NATIVE) = 2026-07-04T09:00+05:30
|
||||
raw DB value for NATIVE offset column = 2026-07-04 09:00:00+05:30 <- unchanged
|
||||
round-tripped OffsetDateTime (NATIVE) = 2026-07-04T09:00+05:30
|
||||
```
|
||||
|
||||
`hibernate.jdbc.time_zone` converts the wall-clock value of a zone-less `LocalDateTime` into the
|
||||
configured zone before it is bound to the JDBC driver -- the literal bytes stored in the database
|
||||
shift, even though the application-level round trip through the *same* Hibernate configuration is
|
||||
transparent (you get your `LocalDateTime` back unchanged). The danger is exactly the
|
||||
"looks fine in the app, wrong when another tool reads the table directly" class of bug. It has
|
||||
**no effect** on a value that already carries an explicit offset (`OffsetDateTime` with
|
||||
`TimeZoneStorage.NATIVE`) -- that value is bound and stored exactly as given, confirmed by both
|
||||
the raw column value and the round trip being unchanged.
|
||||
|
||||
Raw output: [`docs/output/datetime-jdbc-time-zone.txt`](output/datetime-jdbc-time-zone.txt).
|
||||
|
||||
## Summary
|
||||
|
||||
| Claim | Verified value |
|
||||
|---|---|
|
||||
| `@Temporal` deprecated since | Jakarta Persistence 3.2 (confirmed via `javap -v`) |
|
||||
| `@Temporal` misapplied to `java.time` | Logs a deprecation warning, does not fail |
|
||||
| `TimeZoneStorageType` constants | NATIVE, NORMALIZE, NORMALIZE_UTC, COLUMN, AUTO, DEFAULT (6, not 5) |
|
||||
| Hibernate 7.4.5 default storage on H2 | Behaves like NATIVE (dialect-derived, not a fixed constant) |
|
||||
| JVM-zone hazard | Only `NORMALIZE` changes displayed offset when JVM zone changes |
|
||||
| `COLUMN` mode DDL | Adds a companion `_tz integer` column |
|
||||
| Nanosecond round trip | H2 rounds to microseconds; HSQLDB truncates to microseconds |
|
||||
| `@Column(precision=9)` on a temporal field | No effect on generated DDL or stored precision |
|
||||
| `hibernate.jdbc.time_zone` | Shifts raw stored value for zone-less types; no effect on explicit-offset types |
|
||||
|
||||
`@Temporal`'s deprecation is visible in the class file itself — see [`docs/output/datetime-javap-temporal-deprecated.txt`](output/datetime-javap-temporal-deprecated.txt).
|
||||
|
||||
[← Previous: 12 — Association mappings](12-association-mappings.md) | [Next: 14 — Named queries →](14-named-queries.md)
|
||||
Executable
+210
@@ -0,0 +1,210 @@
|
||||
# 14 — Named queries: what startup validation, caching, and "faster" actually mean
|
||||
|
||||
[← Previous: 13 — Date and time mapping](13-date-and-time-mapping.md) | [Back to README →](../README.md)
|
||||
|
||||
Backs [ankurm.com: Hibernate 7 named queries](https://ankurm.com/master-hibernate-7-named-queries-clean-efficient-and-maintainable-data-access/).
|
||||
|
||||
Everything below comes from JUnit tests in [`src/test/java/com/ankurm/hibernatedemo/namedquery/`](../src/test/java/com/ankurm/hibernatedemo/namedquery/)
|
||||
(and one deliberately-broken entity, [`BrokenNamedQueryEmployee`](../src/test/java/com/ankurm/brokenprobe/BrokenNamedQueryEmployee.java), kept outside the app's scanned package, explained below),
|
||||
run against Hibernate 7.4.5.Final / H2 2.4.240.
|
||||
|
||||
## Startup validation
|
||||
|
||||
`hibernate.query.startup_check` is a real setting -- confirmed present as
|
||||
`org.hibernate.cfg.QuerySettings.QUERY_STARTUP_CHECKING` -- and it does exactly what the name
|
||||
suggests.
|
||||
|
||||
A deliberately broken `@NamedQuery` (`e.firsNam` instead of `e.firstName`) fails
|
||||
`SessionFactory` construction with the check enabled (Hibernate's default):
|
||||
|
||||
```
|
||||
wrapper class: org.hibernate.query.NamedQueryValidationException
|
||||
verbatim message: Errors in named queries:
|
||||
[1] Error in query named 'BrokenNamedQueryEmployee.badProperty': Could not resolve attribute
|
||||
'firsNam' of 'com.ankurm.brokenprobe.BrokenNamedQueryEmployee'
|
||||
[SELECT e FROM BrokenNamedQueryEmployee e WHERE e.firsNam = :name]
|
||||
```
|
||||
|
||||
With `hibernate.query.startup_check=false`, the identical broken entity builds a
|
||||
`SessionFactory` successfully. The same broken query only fails once it is actually executed --
|
||||
and with a **different** exception:
|
||||
|
||||
```
|
||||
class: java.lang.IllegalArgumentException
|
||||
message: org.hibernate.query.sqm.UnknownPathException: Could not resolve attribute 'firsNam' ...
|
||||
```
|
||||
|
||||
`NamedQueryValidationException` at boot vs. `IllegalArgumentException` (wrapping
|
||||
`UnknownPathException`) at call time -- the contrast is the article's best argument for leaving
|
||||
the check on: the failure mode changes from "the deploy pipeline stops" to "a user's request
|
||||
throws in production."
|
||||
|
||||
**Engineering note on how this was reproduced safely**: the broken entity
|
||||
(`com.ankurm.brokenprobe.BrokenNamedQueryEmployee`) lives outside the
|
||||
`com.ankurm.hibernatedemo` package tree on purpose. Spring Boot's default JPA entity scan walks
|
||||
every subpackage under the `@SpringBootApplication` class's package
|
||||
(`com.ankurm.hibernatedemo`), so a broken `@NamedQuery` anywhere in that tree would fail
|
||||
`@SpringBootTest` context bootstrap for *every* test in this shared repository, not just this
|
||||
one. [`NamedQueryStartupValidationTest`](../src/test/java/com/ankurm/hibernatedemo/namedquery/NamedQueryStartupValidationTest.java) instead uses a fully standalone Hibernate bootstrap
|
||||
(`StandardServiceRegistryBuilder` + `MetadataSources`, no Spring involved at all) so the broken
|
||||
entity never touches the shared application context.
|
||||
|
||||
Raw output: [`docs/output/namedquery-startup-validation.txt`](output/namedquery-startup-validation.txt).
|
||||
|
||||
## `jakarta.persistence.NamedQuery` vs `org.hibernate.annotations.NamedQuery`
|
||||
|
||||
Both exist and are usable in Hibernate 7.4.5 / Jakarta Persistence 3.2, confirmed via `javap`.
|
||||
The JPA-standard annotation is minimal:
|
||||
|
||||
```
|
||||
jakarta.persistence.NamedQuery: name(), query(), resultClass(), lockMode(), hints()
|
||||
```
|
||||
|
||||
Hibernate's own extends that meaningfully, exercised on [`HibernateExtraEmployee`](../src/main/java/com/ankurm/hibernatedemo/namedquery/HibernateExtraEmployee.java):
|
||||
|
||||
```
|
||||
org.hibernate.annotations.NamedQuery: name(), query(), resultClass(), flush(), flushMode(),
|
||||
cacheable(), cacheRegion(), fetchSize(), timeout(), comment(),
|
||||
cacheStoreMode(), cacheRetrieveMode(), cacheMode(), readOnly()
|
||||
```
|
||||
|
||||
`cacheable`, `flush`/`flushMode`, `timeout`, and `readOnly` have no JPA-standard equivalent on
|
||||
`@NamedQuery` itself (JPA's `hints()` array can express some of these indirectly via magic
|
||||
strings, but Hibernate's annotation gives typed attributes).
|
||||
|
||||
**One of these extras demonstrated actually taking effect**: `cacheable = true` on
|
||||
`HibernateExtraEmployee.cacheableFindAll` genuinely populates the second-level query cache (JCache
|
||||
+ Ehcache configured explicitly for this test, since it is off by default -- see
|
||||
[chapter 09's writeup of the classpath-pollution trap](09-testing-in-memory-databases.md#hibernate-jcache-on-the-classpath-turns-on-l2-for-everyone-whether-you-asked-or-not)
|
||||
for why that's off by default repo-wide). Two separate
|
||||
`EntityManager`s, same query, `Statistics` counters:
|
||||
|
||||
```
|
||||
cacheable=true named query: puts after 1st run = 1, cache hits after 2nd run = 1
|
||||
```
|
||||
|
||||
The put on the first call and the hit on the second are both real, measured, not assumed.
|
||||
|
||||
Raw output: [`docs/output/namedquery-execution-and-projections.txt`](output/namedquery-execution-and-projections.txt).
|
||||
|
||||
## `@NamedNativeQuery` + `@SqlResultSetMapping`, and the JPA 3.2 alternative
|
||||
|
||||
A `@NamedNativeQuery` mapped via `@SqlResultSetMapping` with `@ConstructorResult` into a plain
|
||||
DTO class ([`EmployeeDto`](../src/main/java/com/ankurm/hibernatedemo/namedquery/EmployeeDto.java), on [`NqEmployee`](../src/main/java/com/ankurm/hibernatedemo/namedquery/NqEmployee.java)) works exactly as documented, per [`NamedQueryExecutionTest`](../src/test/java/com/ankurm/hibernatedemo/namedquery/NamedQueryExecutionTest.java):
|
||||
|
||||
```
|
||||
Employee.byNativeDto(ACTIVE): [EmployeeDto{id=1, firstName=Native1}]
|
||||
```
|
||||
|
||||
**Jakarta Persistence 3.2 does allow a `record` as a JPQL constructor-expression target** --
|
||||
tested directly, not merely inferred from the spec text:
|
||||
|
||||
```java
|
||||
record EmployeeRecordDto(Long id, String firstName) {}
|
||||
|
||||
SELECT NEW com.ankurm.hibernatedemo.namedquery.EmployeeRecordDto(e.id, e.firstName)
|
||||
FROM NqEmployee e WHERE e.firstName = :name
|
||||
```
|
||||
|
||||
```
|
||||
JPQL constructor expression into a record: [EmployeeRecordDto[id=3, firstName=RecordTest]]
|
||||
```
|
||||
|
||||
No special configuration needed -- a canonical [`EmployeeRecordDto`](../src/main/java/com/ankurm/hibernatedemo/namedquery/EmployeeRecordDto.java) constructor is matched exactly like any
|
||||
other multi-argument constructor.
|
||||
|
||||
Raw output: [`docs/output/namedquery-execution-and-projections.txt`](output/namedquery-execution-and-projections.txt).
|
||||
|
||||
## Named queries in `orm.xml`
|
||||
|
||||
A named query defined purely in [`META-INF/orm.xml`](../src/main/resources/META-INF/orm.xml) (no annotation at all,
|
||||
[`XmlQueryEmployee`](../src/main/java/com/ankurm/hibernatedemo/namedquery/XmlQueryEmployee.java)`.findBySalaryAboveXml`) is picked up automatically by Spring Boot's default JPA
|
||||
bootstrap -- **no `persistence.xml` and no explicit `<mapping-file>` registration required**; it
|
||||
is discovered simply by being at the conventional `META-INF/orm.xml` classpath location. This is
|
||||
the same "orm.xml just works with zero registration" theme chapter 04 documents for
|
||||
`spring.jpa.mapping-resources`-driven entities -- see
|
||||
[`04 — Annotations vs. XML mappings`](04-annotations-vs-xml.md#ormxml-really-can-define-an-entire-entity-annotation-free).
|
||||
|
||||
It works side by side with an annotation-defined named query on the same entity, per [`OrmXmlNamedQueryTest`](../src/test/java/com/ankurm/hibernatedemo/namedquery/OrmXmlNamedQueryTest.java):
|
||||
|
||||
```
|
||||
annotation-defined named query result: 1 rows
|
||||
orm.xml-defined named query result: 1 rows
|
||||
```
|
||||
|
||||
And when `orm.xml` defines a named query with the **same name** as one already declared via
|
||||
`@NamedQuery` on the entity, the XML definition wins -- proven by giving the annotated version a
|
||||
deliberately wrong predicate (`salary < 0`) and the XML version the correct one:
|
||||
|
||||
```
|
||||
XmlQueryEmployee.overridden (annotation says salary<0, orm.xml says salary>:min): 1 rows
|
||||
```
|
||||
|
||||
If the annotation had won, this would have returned 0 rows.
|
||||
|
||||
Raw output: [`docs/output/namedquery-ormxml.txt`](output/namedquery-ormxml.txt).
|
||||
|
||||
## Does pre-parsing actually help? (Measured, not assumed)
|
||||
|
||||
The common claim is that named queries are faster because they are "pre-parsed." Hibernate's own
|
||||
query-plan cache is keyed by the **query string**, not by whether the string came from a
|
||||
`@NamedQuery` or an inline JPQL literal -- so after the very first execution of either, both
|
||||
paths hit the same cached AST/plan. [`NamedQueryPerformanceTest`](../src/test/java/com/ankurm/hibernatedemo/namedquery/NamedQueryPerformanceTest.java) measures this directly: 500
|
||||
warmup iterations, then 5000 measured iterations of a named query and the identical inline JPQL
|
||||
string, interleaved call-by-call (to cancel out JIT/GC ordering bias) on a shared, otherwise-idle
|
||||
in-memory H2 database:
|
||||
|
||||
```
|
||||
run 1: named avg=124.18 us/call, inline avg=113.77 us/call, ratio (named/inline)=1.09
|
||||
run 2: named avg=136.74 us/call, inline avg=128.27 us/call, ratio (named/inline)=1.07
|
||||
```
|
||||
|
||||
**Honest finding**: across two runs the ratio stayed within ~10% either direction of 1.0, which
|
||||
is noise for a shared sandbox container, not a real effect. We could not measure a performance
|
||||
advantage for named queries over the identical inline JPQL string once both have been warmed up.
|
||||
The commonly repeated "named queries are faster because they're pre-parsed" claim should be
|
||||
retired as stated -- the real, verifiable benefits of named queries are the ones demonstrated
|
||||
above: fail-fast startup validation, a place to attach Hibernate-specific extras like
|
||||
`cacheable`, and centralizing query text -- not raw per-call execution speed.
|
||||
|
||||
Raw output: [`docs/output/namedquery-preparse-performance.txt`](output/namedquery-preparse-performance.txt).
|
||||
|
||||
## `getSingleResultOrNull()` vs `getSingleResult()`
|
||||
|
||||
Both confirmed present via `javap jakarta.persistence.Query` (Jakarta Persistence 3.2.0):
|
||||
|
||||
```
|
||||
public abstract java.lang.Object getSingleResult();
|
||||
public abstract java.lang.Object getSingleResultOrNull();
|
||||
```
|
||||
|
||||
Behavior on zero rows, from a real run:
|
||||
|
||||
```
|
||||
getSingleResultOrNull() on zero rows returned: null
|
||||
getSingleResult() on zero rows threw: jakarta.persistence.NoResultException:
|
||||
No result found for query [SELECT e FROM NqEmployee e WHERE e.firstName = :n]
|
||||
```
|
||||
|
||||
`getSingleResultOrNull()` (added in Jakarta Persistence 3.2) is the null-returning alternative
|
||||
that avoids a try/catch around `NoResultException` for the common "may or may not exist" lookup.
|
||||
Chapter 05 covers the same method on the more specific `TypedQuery` interface -- see
|
||||
[`05 — JPA persistence annotations`](05-jpa-persistence-annotations.md#whats-actually-new-in-jakarta-persistence-32-verified-via-javap-on-jakartapersistence-api-320jar).
|
||||
|
||||
Raw output: [`docs/output/namedquery-execution-and-projections.txt`](output/namedquery-execution-and-projections.txt).
|
||||
|
||||
## Summary
|
||||
|
||||
| Claim | Verified value |
|
||||
|---|---|
|
||||
| `hibernate.query.startup_check` | Exists (`QuerySettings.QUERY_STARTUP_CHECKING`); default behavior fails fast at boot |
|
||||
| Broken named query, check enabled | `NamedQueryValidationException` at `SessionFactory` build |
|
||||
| Broken named query, check disabled | Boots fine; fails at call time with `IllegalArgumentException`/`UnknownPathException` |
|
||||
| `jakarta.persistence.NamedQuery` vs Hibernate's | Hibernate's adds cacheable/flush/timeout/readOnly/comment/cache* |
|
||||
| `cacheable=true` | Measurably populates and hits the 2nd-level query cache |
|
||||
| Record as JPQL constructor target | Works directly, JPA 3.2 |
|
||||
| `orm.xml` named queries | Auto-discovered with no `persistence.xml`; override same-named annotations |
|
||||
| Named query vs inline JPQL speed | No measurable difference after warmup (ratio ~1.0-1.1 across runs) |
|
||||
| `getSingleResultOrNull()` | Present since JPA 3.2; returns null instead of throwing `NoResultException` |
|
||||
|
||||
[← Previous: 13 — Date and time mapping](13-date-and-time-mapping.md) | [Back to README →](../README.md)
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
allocationSize=50, batch_size=1, 30 rows -> prepareStatementCount=32
|
||||
allocationSize=50, batch_size=10, 30 rows -> prepareStatementCount=2
|
||||
allocationSize=50, batch_size=25, 30 rows -> prepareStatementCount=2
|
||||
allocationSize=50, batch_size=50, 30 rows -> prepareStatementCount=2
|
||||
allocationSize=50, batch_size=25, 30 rows -> prepareStatementCount=3
|
||||
allocationSize=25, batch_size=25, 30 rows -> prepareStatementCount=4
|
||||
allocationSize=10, batch_size=25, 30 rows -> prepareStatementCount=5
|
||||
allocationSize=1, batch_size=25, 30 rows -> prepareStatementCount=31
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
cascade=ALL + orphanRemoval=true, in-place removeIf(): books before=3, books after=1
|
||||
orphanRemoval=false: after removing book2 from author.books and flushing, book2 row still exists = true, author_id still = 1
|
||||
owning side test: mutated only author2.getBooks().add(book) (inverse side), book.author after flush = null (FK not written)
|
||||
cascade=ALL + orphanRemoval=true, reassigning the collection reference -- wrapper: jakarta.persistence.RollbackException
|
||||
cascade=ALL + orphanRemoval=true, reassigning the collection reference -- root cause: org.hibernate.HibernateException: A collection with orphan deletion was no longer referenced by the owning entity instance: com.ankurm.hibernatedemo.association.CascadeAuthor.books
|
||||
/* DELETE FROM CascadeBook */ delete from cascade_book cb1_0
|
||||
Hibernate: /* DELETE FROM CascadeBook */ delete from cascade_book cb1_0
|
||||
/* delete for com.ankurm.hibernatedemo.association.CascadeBook */delete from cascade_book where id=?
|
||||
Hibernate: /* delete for com.ankurm.hibernatedemo.association.CascadeBook */delete from cascade_book where id=?
|
||||
/* delete for com.ankurm.hibernatedemo.association.CascadeBook */delete from cascade_book where id=?
|
||||
Hibernate: /* delete for com.ankurm.hibernatedemo.association.CascadeBook */delete from cascade_book where id=?
|
||||
/* DELETE FROM CascadeBook */ delete from cascade_book cb1_0
|
||||
Hibernate: /* DELETE FROM CascadeBook */ delete from cascade_book cb1_0
|
||||
/* DELETE FROM CascadeBook */ delete from cascade_book cb1_0
|
||||
Hibernate: /* DELETE FROM CascadeBook */ delete from cascade_book cb1_0
|
||||
/* DELETE FROM CascadeBook */ delete from cascade_book cb1_0
|
||||
Hibernate: /* DELETE FROM CascadeBook */ delete from cascade_book cb1_0
|
||||
@@ -0,0 +1,6 @@
|
||||
Fix #2 (two queries): 2 queries fired, books=4, awards=3
|
||||
Cartesian product: 4 books x 3 awards for 1 author -> raw SQL join rows = 12, distinct entities returned = 1
|
||||
MultipleBagFetchException reproduction -- wrapper class: java.lang.IllegalArgumentException
|
||||
MultipleBagFetchException reproduction -- root cause class: org.hibernate.loader.MultipleBagFetchException
|
||||
MultipleBagFetchException reproduction -- verbatim message: cannot simultaneously fetch multiple bags: [com.ankurm.hibernatedemo.association.BagAuthorList.awards, com.ankurm.hibernatedemo.association.BagAuthorList.books]
|
||||
Fix #1 (Set instead of List): 1 distinct authors returned, 1 queries fired
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
@BatchSize(10): 100 authors, 11 queries (expected 11 = 1 + ceil(100/10)), books touched = 300
|
||||
@EntityGraph (fetchgraph hint): 100 authors, 1 queries, books touched = 300
|
||||
JPQL JOIN FETCH: 100 authors, 1 queries, books touched = 300
|
||||
=== Side-by-side query counts for 100 authors x 3 books each ===
|
||||
naive lazy iteration : 101 queries
|
||||
JPQL JOIN FETCH : 1 queries
|
||||
@EntityGraph : 1 queries
|
||||
@BatchSize(10) : 11 queries
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
LazyUser.find(): 2 queries fired BEFORE touching getProfile() at all (expected 2: user + eager profile join/select)
|
||||
after touching getProfile(): 2 queries total (profile=loaded)
|
||||
MiUser.find() (no mappedBy field at all): 1 query
|
||||
explicit MiProfile.find() by shared PK when actually needed: 2 total queries
|
||||
select lu1_0.id,lu1_0.username from lazy_user lu1_0 where lu1_0.id=?
|
||||
Hibernate: select lu1_0.id,lu1_0.username from lazy_user lu1_0 where lu1_0.id=?
|
||||
select lp1_0.id,lp1_0.bio,lp1_0.user_id from lazy_profile lp1_0 where lp1_0.user_id=?
|
||||
Hibernate: select lp1_0.id,lp1_0.bio,lp1_0.user_id from lazy_profile lp1_0 where lp1_0.user_id=?
|
||||
select mu1_0.id,mu1_0.username from mi_user mu1_0 where mu1_0.id=?
|
||||
Hibernate: select mu1_0.id,mu1_0.username from mi_user mu1_0 where mu1_0.id=?
|
||||
select mp1_0.id,mp1_0.bio,u1_0.id,u1_0.username from mi_profile mp1_0 join mi_user u1_0 on u1_0.id=mp1_0.id where mp1_0.id=?
|
||||
Hibernate: select mp1_0.id,mp1_0.bio,u1_0.id,u1_0.username from mi_profile mp1_0 join mi_user u1_0 on u1_0.id=mp1_0.id where mp1_0.id=?
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
ROUNDTRIP localDate = 2026-03-15
|
||||
ROUNDTRIP localDateTime = 2026-03-15T10:30:45
|
||||
ROUNDTRIP localTime = 10:30:45
|
||||
ROUNDTRIP instant = 2026-03-15T10:30:45Z
|
||||
ROUNDTRIP offsetDateTime = 2026-03-15T10:30:45+05:30
|
||||
ROUNDTRIP zonedDateTime = 2026-03-15T10:30:45+01:00
|
||||
ROUNDTRIP legacyDateAsDate = 2026-03-15
|
||||
ROUNDTRIP legacyDateAsTimestamp = 2026-03-15 10:30:45.0
|
||||
ROUNDTRIP legacyDateNoTemporal = 2026-03-15 10:30:45.0 (class=class java.sql.Timestamp)
|
||||
ROUNDTRIP legacyCalendar = Sun Mar 15 10:30:45 IST 2026
|
||||
JVM default timezone during this run = Asia/Calcutta
|
||||
create table temporal_types (id bigint generated by default as identity, instant timestamp(6) with time zone, legacy_calendar timestamp(6), legacy_date_as_date date, legacy_date_as_timestamp timestamp(6), legacy_date_no_temporal timestamp(6), local_date date, local_date_time timestamp(6), local_time time(0), offset_date_time timestamp(6) with time zone, zoned_date_time timestamp(6) with time zone, primary key (id))
|
||||
@@ -0,0 +1,13 @@
|
||||
$ javap -v -cp <jakarta.persistence-api-3.2.0> jakarta.persistence.Temporal | grep -A2 Deprecated
|
||||
#10 = Utf8 Temporal.java
|
||||
#11 = Utf8 Deprecated
|
||||
#12 = Utf8 RuntimeVisibleAnnotations
|
||||
#13 = Utf8 Ljava/lang/Deprecated;
|
||||
#14 = Utf8 since
|
||||
#15 = Utf8 3.2
|
||||
#16 = Utf8 Ljava/lang/annotation/Target;
|
||||
--
|
||||
SourceFile: "Temporal.java"
|
||||
Deprecated: true
|
||||
RuntimeVisibleAnnotations:
|
||||
0: #13(#14=s#15)
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
hibernate.jdbc.time_zone=America/New_York -- original LocalDateTime = 2026-07-04T09:00
|
||||
hibernate.jdbc.time_zone=America/New_York -- raw DB value for LocalDateTime column = 2026-07-03 23:30:00
|
||||
hibernate.jdbc.time_zone=America/New_York -- round-tripped LocalDateTime = 2026-07-04T09:00
|
||||
hibernate.jdbc.time_zone=America/New_York -- original OffsetDateTime (NATIVE) = 2026-07-04T09:00+05:30
|
||||
hibernate.jdbc.time_zone=America/New_York -- raw DB value for NATIVE offset column = 2026-07-04 09:00:00+05:30
|
||||
hibernate.jdbc.time_zone=America/New_York -- round-tripped OffsetDateTime (NATIVE) = 2026-07-04T09:00+05:30
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
H2 2.4.240: original LocalDateTime nanos = 123456789
|
||||
H2 2.4.240: plain column (precision default) nanos = 123457000 (value=2026-01-01T12:00:00.123457)
|
||||
H2 2.4.240: @Column(precision=9) column nanos = 123457000 (value=2026-01-01T12:00:00.123457)
|
||||
H2 2.4.240: original Instant nanos = 123456789
|
||||
H2 2.4.240: plain Instant column nanos = 123457000 (value=2027-01-15T08:00:00.123457Z)
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
HSQLDB 2.7.3: original LocalDateTime nanos = 123456789
|
||||
HSQLDB 2.7.3: plain column (precision default) nanos = 123456000 (value=2026-01-01T12:00:00.123456)
|
||||
HSQLDB 2.7.3: @Column(precision=9) column nanos = 123456000 (value=2026-01-01T12:00:00.123456)
|
||||
HSQLDB 2.7.3: original Instant nanos = 123456789
|
||||
HSQLDB 2.7.3: plain Instant column nanos = 123456000 (value=2027-01-15T08:00:00.123456Z)
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
HHH90000033: Encountered use of deprecated annotation [interface jakarta.persistence.Temporal] at com.ankurm.hibernatedemo.datetime.TemporalOnJavaTimeEntity.instantWithTemporalAnnotation.
|
||||
@Temporal(TIMESTAMP) on Instant field: boot succeeded, round-tripped value = 2026-05-20T09:15:30Z (expected 2026-05-20T09:15:30Z)
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
JVM user.timezone system property = Asia/Calcutta
|
||||
JVM TimeZone.getDefault() = Asia/Calcutta
|
||||
ORIGINAL stored = 2026-06-15T14:00+05:30
|
||||
TZ_MODE no-annotation (default) = 2026-06-15T14:00+05:30
|
||||
TZ_MODE NATIVE = 2026-06-15T14:00+05:30
|
||||
TZ_MODE NORMALIZE = 2026-06-15T14:00+05:30
|
||||
TZ_MODE NORMALIZE_UTC = 2026-06-15T08:30Z
|
||||
TZ_MODE COLUMN = 2026-06-15T14:00+05:30
|
||||
TZ_MODE AUTO = 2026-06-15T14:00+05:30
|
||||
create table tz_storage (id bigint generated by default as identity, auto_col timestamp(6) with time zone, column_mode_col timestamp(6) with time zone, column_mode_col_tz integer, native_col timestamp(6) with time zone, no_annotation_col timestamp(6) with time zone, normalize_col timestamp(6), normalize_utc_col timestamp(6) with time zone, primary key (id))
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
JVM user.timezone system property = America/New_York
|
||||
JVM TimeZone.getDefault() = America/New_York
|
||||
ORIGINAL stored = 2026-06-15T14:00+05:30
|
||||
TZ_MODE no-annotation (default) = 2026-06-15T14:00+05:30
|
||||
TZ_MODE NATIVE = 2026-06-15T14:00+05:30
|
||||
TZ_MODE NORMALIZE = 2026-06-15T04:30-04:00
|
||||
TZ_MODE NORMALIZE_UTC = 2026-06-15T08:30Z
|
||||
TZ_MODE COLUMN = 2026-06-15T14:00+05:30
|
||||
TZ_MODE AUTO = 2026-06-15T14:00+05:30
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
Hibernate: select next value for book_seq
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Effective Java]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [1]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
Hibernate: select next value for book_seq
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Domain-Driven Design]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [2]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Outlives Session]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [3]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Matrix: getReference/getReference]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [4]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Matrix: get/getReference]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [5]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [5]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Matrix: get/get]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [6]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [6]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Proxy Identity]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [7]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [7]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [7]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [999111222]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [999333444]
|
||||
getReference() on a missing id, once accessed, threw: jakarta.persistence.EntityNotFoundException: No row with the given identifier exists for entity [com.ankurm.hibernatedemo.model.Book with id '999333444']
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Matrix: getReference/get]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [8]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [8]
|
||||
get() after getReference(): prepareStatementCount for this call = 1, returned class = com.ankurm.hibernatedemo.model.Book$HibernateProxy
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create table book (id bigint not null, author varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
Hibernate: create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create sequence book_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_seq start with 1 increment by 25
|
||||
Hibernate: select next value for book_seq
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,title,version,id) values (?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Joshua Bloch]
|
||||
binding parameter (2:VARCHAR) <- [Effective Java]
|
||||
binding parameter (3:BIGINT) <- [0]
|
||||
binding parameter (4:BIGINT) <- [1]
|
||||
SEED: inserted Book id=1
|
||||
--- Step 1: session.get() on an existing id ---
|
||||
about to call session.get(Book.class, 1)
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
get() returned: Book{id=1, title=Effective Java, author=Joshua Bloch, version=0}
|
||||
--- Step 2: session.get() on a missing id ---
|
||||
about to call session.get(Book.class, 999001)
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [999001]
|
||||
get() returned: null (no exception thrown)
|
||||
--- Step 3: session.getReference() on an existing id ---
|
||||
getReference() returned proxy of class com.ankurm.hibernatedemo.model.Book$HibernateProxy -- no SELECT above this line
|
||||
now calling proxy.getTitle() ...
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
getTitle() returned 'Effective Java' -- the SELECT for this ran just above this line
|
||||
--- Step 4: session.getReference() on a missing id ---
|
||||
getReference() returned a proxy for a row that does not exist -- no exception yet: com.ankurm.hibernatedemo.model.Book$HibernateProxy
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [999001]
|
||||
accessing the proxy threw jakarta.persistence.EntityNotFoundException: No row with the given identifier exists for entity [com.ankurm.hibernatedemo.model.Book with id '999001']
|
||||
--- Step 5: proxy accessed after its session is closed ---
|
||||
session closed. proxy in hand: com.ankurm.hibernatedemo.model.Book$HibernateProxy
|
||||
accessing the proxy after close threw org.hibernate.LazyInitializationException: Could not initialize proxy [com.ankurm.hibernatedemo.model.Book#1] - no session
|
||||
--- Step 6: proxy identity vs a real loaded instance ---
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
real.getClass() = com.ankurm.hibernatedemo.model.Book
|
||||
proxy.getClass() = com.ankurm.hibernatedemo.model.Book$HibernateProxy
|
||||
proxy instanceof Book.class: true
|
||||
real.getClass() == proxy.getClass(): false
|
||||
real.equals(proxy) before proxy access: false
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
with handling-mode=allow, bulk HQL UPDATE rowsAffected=1
|
||||
row after allowed bulk HQL update: ExchangeRate{id=1, pair=ZAR/USD, rate=1.0000}
|
||||
flush() over 4000 loaded MUTABLE rows (12 cols, no pending changes): 8.62815 ms
|
||||
flush() over 4000 loaded @Immutable rows (12 cols, no pending changes): 2.535115 ms
|
||||
ratio (mutable / immutable) = 3.403455070085578
|
||||
CAVEAT: single-run, shared-container timing -- indicative only, not a benchmark result.
|
||||
in-memory field mutated to 999.9999, about to flush inside a transaction
|
||||
Statistics.getEntityUpdateCount() after mutate+flush = 0
|
||||
reloaded from DB: ExchangeRate{id=3, pair=USD/EUR, rate=0.9200}
|
||||
Session.setReadOnly(entity,true) then mutate+flush -> entityUpdateCount = 0
|
||||
native SQL UPDATE rows=1
|
||||
row after native SQL update: ExchangeRate{id=4, pair=CHF/USD, rate=7.7000}
|
||||
bulk HQL 'update ExchangeRate set ...' on an @Immutable entity threw: org.hibernate.query.sqm.InterpretationException: Error interpreting query [The query attempts to update an immutable entity: [exchange_rate] (set 'hibernate.query.immutable_entity_update_query_handling_mode' to suppress)] [update ExchangeRate set rate = :r where id = :id]
|
||||
adding to an @Immutable collection and flushing threw: jakarta.persistence.RollbackException: Error while committing the transaction [Immutable collection was modified: [com.ankurm.hibernatedemo.immutable.RateWithAuditTrail.auditTrails with owner id '1']]
|
||||
root cause class: org.hibernate.HibernateException message: Immutable collection was modified: [com.ankurm.hibernatedemo.immutable.RateWithAuditTrail.auditTrails with owner id '1']
|
||||
persisted @Immutable+@Version entity, version after insert = 0
|
||||
after mutate+flush, version = 0, rate = 0.0950
|
||||
after EntityManager.remove() on an @Immutable entity, find() returns: null
|
||||
after setDefaultReadOnly(true) + mutate + flush, rate = 6.9000
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
Classfile /tmp/j-immutable/org/hibernate/annotations/Immutable.class
|
||||
Last modified Feb 1, 1980; size 422 bytes
|
||||
SHA-256 checksum 8a49d58789086dfab9871a67e8247e527ef2675d685ac086db603719ca4c5813
|
||||
Compiled from "Immutable.java"
|
||||
public interface org.hibernate.annotations.Immutable extends java.lang.annotation.Annotation
|
||||
minor version: 0
|
||||
major version: 61
|
||||
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
|
||||
this_class: #1 // org/hibernate/annotations/Immutable
|
||||
super_class: #3 // java/lang/Object
|
||||
interfaces: 1, fields: 0, methods: 0, attributes: 2
|
||||
Constant pool:
|
||||
#1 = Class #2 // org/hibernate/annotations/Immutable
|
||||
#2 = Utf8 org/hibernate/annotations/Immutable
|
||||
#3 = Class #4 // java/lang/Object
|
||||
#4 = Utf8 java/lang/Object
|
||||
#5 = Class #6 // java/lang/annotation/Annotation
|
||||
#6 = Utf8 java/lang/annotation/Annotation
|
||||
#7 = Utf8 SourceFile
|
||||
#8 = Utf8 Immutable.java
|
||||
#9 = Utf8 RuntimeVisibleAnnotations
|
||||
#10 = Utf8 Ljava/lang/annotation/Target;
|
||||
#11 = Utf8 value
|
||||
#12 = Utf8 Ljava/lang/annotation/ElementType;
|
||||
#13 = Utf8 TYPE
|
||||
#14 = Utf8 METHOD
|
||||
#15 = Utf8 FIELD
|
||||
#16 = Utf8 Ljava/lang/annotation/Retention;
|
||||
#17 = Utf8 Ljava/lang/annotation/RetentionPolicy;
|
||||
#18 = Utf8 RUNTIME
|
||||
{
|
||||
}
|
||||
SourceFile: "Immutable.java"
|
||||
RuntimeVisibleAnnotations:
|
||||
0: #10(#11=[e#12.#13,e#12.#14,e#12.#15])
|
||||
java.lang.annotation.Target(
|
||||
value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.FIELD]
|
||||
)
|
||||
1: #16(#11=e#17.#18)
|
||||
java.lang.annotation.Retention(
|
||||
value=Ljava/lang/annotation/RetentionPolicy;.RUNTIME
|
||||
)
|
||||
Compiled from "ImmutableEntityUpdateQueryHandlingMode.java"
|
||||
public final class org.hibernate.query.spi.ImmutableEntityUpdateQueryHandlingMode extends java.lang.Enum<org.hibernate.query.spi.ImmutableEntityUpdateQueryHandlingMode> {
|
||||
public static final org.hibernate.query.spi.ImmutableEntityUpdateQueryHandlingMode ALLOW;
|
||||
public static final org.hibernate.query.spi.ImmutableEntityUpdateQueryHandlingMode WARNING;
|
||||
public static final org.hibernate.query.spi.ImmutableEntityUpdateQueryHandlingMode EXCEPTION;
|
||||
private static final org.hibernate.query.spi.ImmutableEntityUpdateQueryHandlingMode[] $VALUES;
|
||||
public static org.hibernate.query.spi.ImmutableEntityUpdateQueryHandlingMode[] values();
|
||||
public static org.hibernate.query.spi.ImmutableEntityUpdateQueryHandlingMode valueOf(java.lang.String);
|
||||
private org.hibernate.query.spi.ImmutableEntityUpdateQueryHandlingMode();
|
||||
public static org.hibernate.query.spi.ImmutableEntityUpdateQueryHandlingMode interpret(java.lang.Object);
|
||||
private static org.hibernate.query.spi.ImmutableEntityUpdateQueryHandlingMode[] $values();
|
||||
static {};
|
||||
}
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create table book (id bigint not null, author varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
Hibernate: create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create sequence book_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_seq start with 1 increment by 25
|
||||
--- inserting 30 WidgetIdentity rows (GenerationType.IDENTITY) ---
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-1]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-2]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-3]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-4]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-5]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-6]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-7]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-8]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-9]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-10]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-11]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-12]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-13]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-14]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-15]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-16]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-17]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-18]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-19]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-20]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-21]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-22]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-23]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-24]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-25]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-26]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-27]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-28]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-29]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetIdentity */insert into widget_identity (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [identity-30]
|
||||
entityInsertCount = 30
|
||||
prepareStatementCount = 30
|
||||
(with IDENTITY, expect prepareStatementCount to land close to entityInsertCount -- each insert has to go to the database immediately to hand back the generated key, so there is nothing left for hibernate.jdbc.batch_size to batch)
|
||||
Executable
+104
@@ -0,0 +1,104 @@
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create table book (id bigint not null, author varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
Hibernate: create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create sequence book_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_seq start with 1 increment by 25
|
||||
--- inserting 30 WidgetSequence rows (GenerationType.SEQUENCE, allocationSize=25) ---
|
||||
Hibernate: select next value for widget_seq
|
||||
Hibernate: select next value for widget_seq
|
||||
Hibernate: select next value for widget_seq
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-1]
|
||||
binding parameter (2:BIGINT) <- [1]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-2]
|
||||
binding parameter (2:BIGINT) <- [2]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-3]
|
||||
binding parameter (2:BIGINT) <- [3]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-4]
|
||||
binding parameter (2:BIGINT) <- [4]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-5]
|
||||
binding parameter (2:BIGINT) <- [5]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-6]
|
||||
binding parameter (2:BIGINT) <- [6]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-7]
|
||||
binding parameter (2:BIGINT) <- [7]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-8]
|
||||
binding parameter (2:BIGINT) <- [8]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-9]
|
||||
binding parameter (2:BIGINT) <- [9]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-10]
|
||||
binding parameter (2:BIGINT) <- [10]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-11]
|
||||
binding parameter (2:BIGINT) <- [11]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-12]
|
||||
binding parameter (2:BIGINT) <- [12]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-13]
|
||||
binding parameter (2:BIGINT) <- [13]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-14]
|
||||
binding parameter (2:BIGINT) <- [14]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-15]
|
||||
binding parameter (2:BIGINT) <- [15]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-16]
|
||||
binding parameter (2:BIGINT) <- [16]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-17]
|
||||
binding parameter (2:BIGINT) <- [17]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-18]
|
||||
binding parameter (2:BIGINT) <- [18]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-19]
|
||||
binding parameter (2:BIGINT) <- [19]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-20]
|
||||
binding parameter (2:BIGINT) <- [20]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-21]
|
||||
binding parameter (2:BIGINT) <- [21]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-22]
|
||||
binding parameter (2:BIGINT) <- [22]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-23]
|
||||
binding parameter (2:BIGINT) <- [23]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-24]
|
||||
binding parameter (2:BIGINT) <- [24]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-25]
|
||||
binding parameter (2:BIGINT) <- [25]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-26]
|
||||
binding parameter (2:BIGINT) <- [26]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-27]
|
||||
binding parameter (2:BIGINT) <- [27]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-28]
|
||||
binding parameter (2:BIGINT) <- [28]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-29]
|
||||
binding parameter (2:BIGINT) <- [29]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.WidgetSequence */insert into widget_sequence (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [sequence-30]
|
||||
binding parameter (2:BIGINT) <- [30]
|
||||
entityInsertCount = 30
|
||||
prepareStatementCount = 4
|
||||
(with SEQUENCE, the id is known before the row is written, so Hibernate can defer and batch the inserts -- expect prepareStatementCount well below entityInsertCount)
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
# Boot 4.1.1: JndiDataSourceAutoConfiguration and spring.datasource.jndi-name -- relocated module
|
||||
# Jar: spring-boot-jdbc-4.1.1.jar (NOT spring-boot-autoconfigure-4.1.1.jar -- that jar has zero 'jndi' matches)
|
||||
|
||||
Compiled from "JndiDataSourceAutoConfiguration.java"
|
||||
public final class org.springframework.boot.jdbc.autoconfigure.JndiDataSourceAutoConfiguration {
|
||||
public org.springframework.boot.jdbc.autoconfigure.JndiDataSourceAutoConfiguration();
|
||||
javax.sql.DataSource dataSource(org.springframework.boot.jdbc.autoconfigure.DataSourceProperties, org.springframework.context.ApplicationContext);
|
||||
private void excludeMBeanIfNecessary(java.lang.Object, java.lang.String, org.springframework.context.ApplicationContext);
|
||||
}
|
||||
|
||||
private java.lang.String password;
|
||||
private java.lang.String jndiName;
|
||||
private org.springframework.boot.jdbc.EmbeddedDatabaseConnection embeddedDatabaseConnection;
|
||||
--
|
||||
public java.lang.String determinePassword();
|
||||
public java.lang.String getJndiName();
|
||||
public void setJndiName(java.lang.String);
|
||||
public org.springframework.boot.jdbc.EmbeddedDatabaseConnection getEmbeddedDatabaseConnection();
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/tmp/tools/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
23:11:22.031 [main] INFO DEMO -- testA bound jdbc/SharedAcrossTests -- no @AfterEach unbind on purpose, to force the pollution
|
||||
23:11:22.102 [main] ERROR org.osjava.sj.jndi.MemoryContext -- bind() jdbc/SharedAcrossTests already bound in MemoryContext{namesToObjects={jdbc/SharedAcrossTests=ds0: url=jdbc:h2:mem:pollution-a;DB_CLOSE_DELAY=-1 user=}, subContexts={jdbc=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@aafcffa, nameInNamespace=jdbc, nameLock=true}}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@6955cb39, nameInNamespace=, nameLock=false}
|
||||
23:11:22.108 [main] INFO DEMO -- testB's bind() of the SAME name testA left behind failed verbatim with: javax.naming.NameAlreadyBoundException: Name jdbc/SharedAcrossTests already bound. Use rebind() to override
|
||||
23:11:22.110 [main] INFO DEMO -- ctx.rebind() instead of ctx.bind() -- the standard fix -- succeeded: ds1: url=jdbc:h2:mem:pollution-b;DB_CLOSE_DELAY=-1 user=
|
||||
23:11:22.115 [main] INFO DEMO -- cleanup: unbound jdbc/SharedAcrossTests so it does not leak into any test that runs after this class
|
||||
23:11:22.379 [main] INFO DEMO -- looked-up DataSource produced a valid connection: jdbc:h2:mem:jnditestdb
|
||||
23:11:22.383 [main] INFO DEMO -- verbatim NoInitialContextException message: Need to specify class name in environment or system property, or in an application resource file: java.naming.factory.initial
|
||||
23:11:22.389 [main] INFO DEMO -- verbatim NameNotFoundException message: java:comp/env/jdbc/DoesNotExist
|
||||
23:11:22.395 [main] ERROR org.osjava.sj.jndi.MemoryContext -- bind() jdbc already bound in MemoryContext{namesToObjects={}, subContexts={java:comp/env/jdbc=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@5ebd56e9, nameInNamespace=java:comp/env/jdbc, nameLock=true}, jdbc=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@aafcffa, nameInNamespace=jdbc, nameLock=true}, java:comp=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@63f34b70, nameInNamespace=java:comp, nameLock=true}, java:=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@641856, nameInNamespace=java:, nameLock=true}, java:comp/env=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@1b58ff9e, nameInNamespace=java:comp/env, nameLock=true}}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@6955cb39, nameInNamespace=, nameLock=false}
|
||||
23:11:22.495 [main] INFO org.hibernate.orm.core -- HHH000001: Hibernate ORM core version 7.4.5.Final
|
||||
23:11:22.793 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
DataSource JNDI name [jdbc/HibernateTestDS]
|
||||
Database JDBC URL [jdbc:h2:mem:hibernate-jndi-test]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Default catalog/schema: HIBERNATE-JNDI-TEST/PUBLIC
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: READ_COMMITTED [default READ_COMMITTED]
|
||||
JDBC fetch size: 100
|
||||
Pool: DataSourceConnectionProvider
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
23:11:23.395 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
23:11:23.523 [main] INFO DEMO -- Hibernate SessionFactory built from JNDI name 'jdbc/HibernateTestDS' ran SELECT 1 -> 1
|
||||
@@ -0,0 +1,5 @@
|
||||
public static final java.lang.String JAKARTA_JTA_DATASOURCE;
|
||||
public static final java.lang.String JAKARTA_NON_JTA_DATASOURCE;
|
||||
public static final java.lang.String DATASOURCE;
|
||||
public static final java.lang.String JPA_JTA_DATASOURCE;
|
||||
public static final java.lang.String JPA_NON_JTA_DATASOURCE;
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
# simple-jndi 0.25.0 jar listing -- confirms actual package layout
|
||||
# The old article's jndi.properties used java.naming.provider.url=org.osjava.sj.memory.MemoryContextFactory
|
||||
# -- there is no org.osjava.sj.memory package in this jar at all. The real class is:
|
||||
2532 2025-02-22 10:12 org/osjava/sj/MemoryContextFactory.class
|
||||
1617 2025-02-22 10:12 org/osjava/sj/SimpleJndiContextFactory$1.class
|
||||
1506 2025-02-22 10:12 org/osjava/sj/MemoryContextFactory$1.class
|
||||
339 2025-02-22 10:12 org/osjava/sj/SimpleContextFactory.class
|
||||
2830 2025-02-22 10:12 org/osjava/sj/SimpleJndiContextFactory.class
|
||||
2320 2025-02-22 10:12 org/osjava/sj/ContextFactory.class
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# Spring Framework 5.3.31 spring-test.jar -- org.springframework.mock.jndi package PRESENT
|
||||
0 2023-11-16 08:03 org/springframework/mock/jndi/
|
||||
4126 2023-11-16 08:03 org/springframework/mock/jndi/SimpleNamingContext$AbstractNamingEnumeration.class
|
||||
262 2023-11-16 08:03 org/springframework/mock/jndi/package-info.class
|
||||
6147 2023-11-16 08:03 org/springframework/mock/jndi/SimpleNamingContextBuilder.class
|
||||
1833 2023-11-16 08:03 org/springframework/mock/jndi/ExpectedLookupTemplate.class
|
||||
1979 2023-11-16 08:03 org/springframework/mock/jndi/SimpleNamingContext$NameClassPairEnumeration.class
|
||||
265 2023-11-16 08:03 org/springframework/mock/jndi/SimpleNamingContext$1.class
|
||||
1808 2023-11-16 08:03 org/springframework/mock/jndi/SimpleNamingContext$BindingEnumeration.class
|
||||
9440 2023-11-16 08:03 org/springframework/mock/jndi/SimpleNamingContext.class
|
||||
|
||||
# Spring Framework 6.0.0 spring-test.jar -- org.springframework.mock.jndi package: NO MATCH (package removed)
|
||||
(no matches -- package is gone)
|
||||
|
||||
# Spring Framework 7.0.9 spring-test.jar (the version this blog batch verifies against) -- same check
|
||||
(no matches -- still gone)
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
# JndiDataSourceResolutionTest + HibernateJndiDataSourceTest + CrossTestPollutionTest
|
||||
# filtered run output, all 7 tests green together (proves the pollution fix works)
|
||||
|
||||
23:11:22.031 [main] INFO DEMO -- testA bound jdbc/SharedAcrossTests -- no @AfterEach unbind on purpose, to force the pollution
|
||||
23:11:22.102 [main] ERROR org.osjava.sj.jndi.MemoryContext -- bind() jdbc/SharedAcrossTests already bound in MemoryContext{namesToObjects={jdbc/SharedAcrossTests=ds0: url=jdbc:h2:mem:pollution-a;DB_CLOSE_DELAY=-1 user=}, subContexts={jdbc=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@aafcffa, nameInNamespace=jdbc, nameLock=true}}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@6955cb39, nameInNamespace=, nameLock=false}
|
||||
23:11:22.108 [main] INFO DEMO -- testB's bind() of the SAME name testA left behind failed verbatim with: javax.naming.NameAlreadyBoundException: Name jdbc/SharedAcrossTests already bound. Use rebind() to override
|
||||
23:11:22.110 [main] INFO DEMO -- ctx.rebind() instead of ctx.bind() -- the standard fix -- succeeded: ds1: url=jdbc:h2:mem:pollution-b;DB_CLOSE_DELAY=-1 user=
|
||||
23:11:22.115 [main] INFO DEMO -- cleanup: unbound jdbc/SharedAcrossTests so it does not leak into any test that runs after this class
|
||||
23:11:22.379 [main] INFO DEMO -- looked-up DataSource produced a valid connection: jdbc:h2:mem:jnditestdb
|
||||
23:11:22.383 [main] INFO DEMO -- verbatim NoInitialContextException message: Need to specify class name in environment or system property, or in an application resource file: java.naming.factory.initial
|
||||
23:11:22.389 [main] INFO DEMO -- verbatim NameNotFoundException message: java:comp/env/jdbc/DoesNotExist
|
||||
23:11:22.395 [main] ERROR org.osjava.sj.jndi.MemoryContext -- bind() jdbc already bound in MemoryContext{namesToObjects={}, subContexts={java:comp/env/jdbc=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@5ebd56e9, nameInNamespace=java:comp/env/jdbc, nameLock=true}, jdbc=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@aafcffa, nameInNamespace=jdbc, nameLock=true}, java:comp=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@63f34b70, nameInNamespace=java:comp, nameLock=true}, java:=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@641856, nameInNamespace=java:, nameLock=true}, java:comp/env=MemoryContext{namesToObjects={}, subContexts={}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@1b58ff9e, nameInNamespace=java:comp/env, nameLock=true}}, env={org.osjava.sj.root=, org.osjava.sj.jndi.shared=true, java.naming.factory.initial=org.osjava.sj.MemoryContextFactory, org.osjava.sj.delimiter=., org.osjava.sj.jndi.ignoreClose=false, jndi.syntax.separator=., jndi.syntax.direction=left_to_right, org.osjava.sj.factory=org.osjava.sj.MemoryContextFactory}, nameParser=org.osjava.sj.jndi.SimpleNameParser@6955cb39, nameInNamespace=, nameLock=false}
|
||||
23:11:22.495 [main] INFO org.hibernate.orm.core -- HHH000001: Hibernate ORM core version 7.4.5.Final
|
||||
23:11:22.793 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
DataSource JNDI name [jdbc/HibernateTestDS]
|
||||
Database JDBC URL [jdbc:h2:mem:hibernate-jndi-test]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Pool: DataSourceConnectionProvider
|
||||
23:11:23.395 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
23:11:23.523 [main] INFO DEMO -- Hibernate SessionFactory built from JNDI name 'jdbc/HibernateTestDS' ran SELECT 1 -> 1
|
||||
|
||||
Tests run: 3 -- JndiDataSourceResolutionTest
|
||||
Tests run: 1 -- HibernateJndiDataSourceTest
|
||||
Tests run: 3 -- CrossTestPollutionTest
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/tmp/tools/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
Failed to initialize JPA EntityManagerFactory: Entity 'com.ankurm.hibernatedemo.mappingstyle.OverrideEntity' has no identifier (every '@Entity' class must declare or inherit at least one '@Id' or '@EmbeddedId' property)
|
||||
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/hibernate/autoconfigure/HibernateJpaConfiguration.class]: Entity 'com.ankurm.hibernatedemo.mappingstyle.OverrideEntity' has no identifier (every '@Entity' class must declare or inherit at least one '@Id' or '@EmbeddedId' property)
|
||||
Application run failed
|
||||
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/hibernate/autoconfigure/HibernateJpaConfiguration.class]: Entity 'com.ankurm.hibernatedemo.mappingstyle.OverrideEntity' has no identifier (every '@Entity' class must declare or inherit at least one '@Id' or '@EmbeddedId' property)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1815)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:603)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:525)
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:333)
|
||||
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:371)
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:331)
|
||||
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201)
|
||||
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:977)
|
||||
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:621)
|
||||
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:756)
|
||||
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:445)
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
|
||||
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:154)
|
||||
at com.ankurm.hibernatedemo.mappingstyle.XmlMappingMetadataCompleteTest.lambda$metadataComplete_ignoresAtIdAnnotation_bootFailsWithNoIdentifier$0(XmlMappingMetadataCompleteTest.java:32)
|
||||
at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:54)
|
||||
at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:35)
|
||||
at org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:3223)
|
||||
at com.ankurm.hibernatedemo.mappingstyle.XmlMappingMetadataCompleteTest.metadataComplete_ignoresAtIdAnnotation_bootFailsWithNoIdentifier(XmlMappingMetadataCompleteTest.java:31)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:701)
|
||||
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:502)
|
||||
at org.junit.jupiter.engine.support.MethodReflectionUtils.invoke(MethodReflectionUtils.java:45)
|
||||
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:61)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:124)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:163)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:148)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:123)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:105)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:99)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:66)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:47)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:39)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:104)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:98)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invokeVoid(InterceptingExecutableInvoker.java:71)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$0(TestMethodTestDescriptor.java:219)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:215)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:157)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:70)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:176)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:36)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:52)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:58)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.executeEngine(EngineExecutionOrchestrator.java:246)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.failOrExecuteEngine(EngineExecutionOrchestrator.java:218)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:179)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:66)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:157)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:65)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:125)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$2(InterceptingLauncher.java:57)
|
||||
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:56)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:125)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithCancellationToken(LauncherAdapter.java:68)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:54)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
|
||||
Caused by: org.hibernate.AnnotationException: Entity 'com.ankurm.hibernatedemo.mappingstyle.OverrideEntity' has no identifier (every '@Entity' class must declare or inherit at least one '@Id' or '@EmbeddedId' property)
|
||||
at org.hibernate.boot.model.internal.InheritanceState.getElementsToProcess(InheritanceState.java:248)
|
||||
at org.hibernate.boot.model.internal.InheritanceState.postProcess(InheritanceState.java:165)
|
||||
at org.hibernate.boot.model.internal.EntityBinder.handleIdentifier(EntityBinder.java:434)
|
||||
at org.hibernate.boot.model.internal.EntityBinder.bindEntityClass(EntityBinder.java:259)
|
||||
at org.hibernate.boot.model.internal.AnnotationBinder.bindClass(AnnotationBinder.java:247)
|
||||
at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:197)
|
||||
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:323)
|
||||
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.coordinateProcessors(MetadataBuildingProcess.java:356)
|
||||
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:209)
|
||||
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1388)
|
||||
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.populateSessionFactoryBuilder(EntityManagerFactoryBuilderImpl.java:1468)
|
||||
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1450)
|
||||
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:93)
|
||||
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:443)
|
||||
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:436)
|
||||
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:411)
|
||||
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:419)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1862)
|
||||
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1811)
|
||||
... 98 common frames omitted
|
||||
RESULT[metadata-complete]: boot FAILED as predicted: org.hibernate.AnnotationException: Entity 'com.ankurm.hibernatedemo.mappingstyle.OverrideEntity' has no identifier (every '@Entity' class must declare or inherit at least one '@Id' or '@EmbeddedId' property)
|
||||
HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
HHH90000028: Support for `<hibernate-mappings/>` is deprecated [RESOURCE : com/ankurm/hibernatedemo/mappingstyle/HbmEmployee.hbm.xml]; migrate to orm.xml or mapping.xml, or enable `hibernate.transform_hbm_xml.enabled` for on the fly transformation
|
||||
drop table if exists hbm_employees cascade
|
||||
create table hbm_employees (id bigint generated by default as identity, first_name varchar(100) not null, email_address varchar(255) unique, primary key (id))
|
||||
insert into hbm_employees (email_address,first_name,id) values (?,?,default)
|
||||
binding parameter (1:VARCHAR) <- [[email protected]]
|
||||
binding parameter (2:VARCHAR) <- [Ada]
|
||||
select he1_0.id,he1_0.email_address,he1_0.first_name from hbm_employees he1_0 where he1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
RESULT[hbm-default-runtime]: persisted+loaded id=1 firstName=Ada [email protected] -- NO hibernate.transform_hbm_xml.enabled setting was applied.
|
||||
create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_override_entity(rn_ integer not null, id bigint, value varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_override_entity(rn_ integer not null, id bigint, value varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
Hibernate: create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
Hibernate: create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
create table override_entity (id bigint not null, xml_name varchar(255), primary key (id))
|
||||
Hibernate: create table override_entity (id bigint not null, xml_name varchar(255), primary key (id))
|
||||
create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
create sequence book_seq start with 1 increment by 50
|
||||
Hibernate: create sequence book_seq start with 1 increment by 50
|
||||
create sequence override_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence override_entity_seq start with 1 increment by 50
|
||||
create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
Hibernate: create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
Hibernate: create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
create sequence widget_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_seq start with 1 increment by 25
|
||||
alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
Hibernate: alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build as described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html#0.3
|
||||
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
|
||||
WARNING: A Java agent has been loaded dynamically (/sessions/intelligent-loving-cori/.m2/repository/net/bytebuddy/byte-buddy-agent/1.18.11/byte-buddy-agent-1.18.11.jar)
|
||||
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
|
||||
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
|
||||
WARNING: Dynamic loading of agents will be disallowed by default in a future release
|
||||
RESULT[override]: runtime column name for OverrideEntity.value = xml_name (annotation said 'annotation_name', orm.xml said 'xml_name')
|
||||
select next value for override_entity_seq
|
||||
Hibernate: select next value for override_entity_seq
|
||||
/* insert for com.ankurm.hibernatedemo.mappingstyle.OverrideEntity */insert into override_entity (xml_name,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.mappingstyle.OverrideEntity */insert into override_entity (xml_name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [hello]
|
||||
binding parameter (2:BIGINT) <- [1]
|
||||
/* dynamic native SQL query */ select xml_name from override_entity where id = 1
|
||||
Hibernate: /* dynamic native SQL query */ select xml_name from override_entity where id = 1
|
||||
RESULT[override]: native query against column 'xml_name' returned: hello
|
||||
HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
drop table if exists hbm_employees cascade
|
||||
create table hbm_employees (id bigint generated by default as identity, first_name varchar(100) not null, email_address varchar(255) unique, primary key (id))
|
||||
RESULT[transform=true]: BOOT SUCCEEDED, SessionFactory built WITH hibernate.transform_hbm_xml.enabled=true
|
||||
HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
HHH90000028: Support for `<hibernate-mappings/>` is deprecated [RESOURCE : com/ankurm/hibernatedemo/mappingstyle/HbmEmployee.hbm.xml]; migrate to orm.xml or mapping.xml, or enable `hibernate.transform_hbm_xml.enabled` for on the fly transformation
|
||||
drop table if exists hbm_employees cascade
|
||||
create table hbm_employees (id bigint generated by default as identity, first_name varchar(100) not null, email_address varchar(255) unique, primary key (id))
|
||||
RESULT[default]: BOOT SUCCEEDED, SessionFactory built without hibernate.transform_hbm_xml.enabled
|
||||
create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_override_entity(rn_ integer not null, id bigint, value varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_override_entity(rn_ integer not null, id bigint, value varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create table mapping_xml_naturalid_widgets (id bigint generated by default as identity, name varchar(255), sku varchar(255) not null, primary key (id))
|
||||
Hibernate: create table mapping_xml_naturalid_widgets (id bigint generated by default as identity, name varchar(255), sku varchar(255) not null, primary key (id))
|
||||
alter table if exists override_entity add column annotation_name varchar(255)
|
||||
Hibernate: alter table if exists override_entity add column annotation_name varchar(255)
|
||||
alter table if exists mapping_xml_naturalid_widgets drop constraint if exists UKgsgrv3pg0aypajhwtinus0j90
|
||||
Hibernate: alter table if exists mapping_xml_naturalid_widgets drop constraint if exists UKgsgrv3pg0aypajhwtinus0j90
|
||||
alter table if exists mapping_xml_naturalid_widgets add constraint UKgsgrv3pg0aypajhwtinus0j90 unique (sku)
|
||||
Hibernate: alter table if exists mapping_xml_naturalid_widgets add constraint UKgsgrv3pg0aypajhwtinus0j90 unique (sku)
|
||||
/* insert for com.ankurm.hibernatedemo.mappingstyle.MappingXmlNaturalIdEntity */insert into mapping_xml_naturalid_widgets (name,sku,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.mappingstyle.MappingXmlNaturalIdEntity */insert into mapping_xml_naturalid_widgets (name,sku,id) values (?,?,default)
|
||||
binding parameter (1:VARCHAR) <- [XML Widget]
|
||||
binding parameter (2:VARCHAR) <- [SKU-XML-1]
|
||||
select mxnie1_0.id,mxnie1_0.name,mxnie1_0.sku from mapping_xml_naturalid_widgets mxnie1_0 where mxnie1_0.sku=?
|
||||
Hibernate: select mxnie1_0.id,mxnie1_0.name,mxnie1_0.sku from mapping_xml_naturalid_widgets mxnie1_0 where mxnie1_0.sku=?
|
||||
binding parameter (1:VARCHAR) <- [SKU-XML-1]
|
||||
RESULT[mapping-xml-natural-id]: session.byNaturalId() resolved an entity whose @NaturalId-equivalent was declared ENTIRELY in Hibernate's native mapping.xml dialect, zero Java annotations. name=XML Widget
|
||||
create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_override_entity(rn_ integer not null, id bigint, value varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_override_entity(rn_ integer not null, id bigint, value varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create table xml_only_widgets (id bigint generated by default as identity, label_text varchar(80), primary key (id))
|
||||
Hibernate: create table xml_only_widgets (id bigint generated by default as identity, label_text varchar(80), primary key (id))
|
||||
/* insert for com.ankurm.hibernatedemo.mappingstyle.OrmXmlOnlyEntity */insert into xml_only_widgets (label_text,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.mappingstyle.OrmXmlOnlyEntity */insert into xml_only_widgets (label_text,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [mapped-by-orm-xml-only]
|
||||
/* select o from OrmXmlOnlyEntity o where o.label = :label */ select oxoe1_0.id,oxoe1_0.label_text from xml_only_widgets oxoe1_0 where oxoe1_0.label_text=?
|
||||
Hibernate: /* select o from OrmXmlOnlyEntity o where o.label = :label */ select oxoe1_0.id,oxoe1_0.label_text from xml_only_widgets oxoe1_0 where oxoe1_0.label_text=?
|
||||
binding parameter (1:VARCHAR) <- [mapped-by-orm-xml-only]
|
||||
RESULT[orm-xml-only]: persisted+queried id=1 via JPQL against entity mapped ENTIRELY by orm.xml (table xml_only_widgets), zero annotations on the Java class.
|
||||
HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
HHH90000028: Support for `<hibernate-mappings/>` is deprecated [RESOURCE : com/ankurm/hibernatedemo/mappingstyle/HbmEmployee.hbm.xml]; migrate to orm.xml or mapping.xml, or enable `hibernate.transform_hbm_xml.enabled` for on the fly transformation
|
||||
drop table if exists hbm_employees cascade
|
||||
create table hbm_employees (id bigint generated by default as identity, first_name varchar(100) not null, email_address varchar(255) unique, primary key (id))
|
||||
RESULT[transform=false]: BOOT SUCCEEDED even with transform_hbm_xml.enabled=false
|
||||
Executable
+82
@@ -0,0 +1,82 @@
|
||||
Hibernate: select next value for book_seq
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [USER_EDIT]
|
||||
binding parameter (3:VARCHAR) <- [Silent Overwrite]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [1]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
Hibernate: /* update for com.ankurm.hibernatedemo.model.Book */update book set author=?,status=?,title=?,version=? where id=? and version=?
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [ADMIN_EDIT]
|
||||
binding parameter (3:VARCHAR) <- [Silent Overwrite]
|
||||
binding parameter (4:BIGINT) <- [1]
|
||||
binding parameter (5:BIGINT) <- [1]
|
||||
binding parameter (6:BIGINT) <- [0]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
Hibernate: select next value for book_seq
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Lazy Collection Book]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [2]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Note */insert into note (book_id,text,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
binding parameter (2:VARCHAR) <- [first note]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version,n1_0.book_id,n1_0.id,n1_0.text from book b1_0 left join note n1_0 on b1_0.id=n1_0.book_id where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
Hibernate: /* update for com.ankurm.hibernatedemo.model.Book */update book set author=?,status=?,title=?,version=? where id=? and version=?
|
||||
binding parameter (1:VARCHAR) <- [Edited While Detached]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Lazy Collection Book]
|
||||
binding parameter (4:BIGINT) <- [1]
|
||||
binding parameter (5:BIGINT) <- [2]
|
||||
binding parameter (6:BIGINT) <- [0]
|
||||
merge() initialized the LAZY notes collection because CascadeType.MERGE forces traversal of it
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Test Author]
|
||||
binding parameter (2:VARCHAR) <- [DRAFT]
|
||||
binding parameter (3:VARCHAR) <- [Managed + Detached]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [3]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
Hibernate: /* update for com.ankurm.hibernatedemo.model.Book */update book set author=?,status=?,title=?,version=? where id=? and version=?
|
||||
binding parameter (1:VARCHAR) <- [Changed On The Detached Copy]
|
||||
binding parameter (2:VARCHAR) <- [DRAFT]
|
||||
binding parameter (3:VARCHAR) <- [Managed + Detached]
|
||||
binding parameter (4:BIGINT) <- [1]
|
||||
binding parameter (5:BIGINT) <- [3]
|
||||
binding parameter (6:BIGINT) <- [0]
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,status,title,version,id) values (?,?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Robert C. Martin]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Clean Code]
|
||||
binding parameter (4:BIGINT) <- [0]
|
||||
binding parameter (5:BIGINT) <- [4]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [4]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [4]
|
||||
Hibernate: /* update for com.ankurm.hibernatedemo.model.Book */update book set author=?,status=?,title=?,version=? where id=? and version=?
|
||||
binding parameter (1:VARCHAR) <- [Robert C. Martin]
|
||||
binding parameter (2:VARCHAR) <- [null]
|
||||
binding parameter (3:VARCHAR) <- [Clean Code (2nd Edition)]
|
||||
binding parameter (4:BIGINT) <- [1]
|
||||
binding parameter (5:BIGINT) <- [4]
|
||||
binding parameter (6:BIGINT) <- [0]
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version,n1_0.book_id,n1_0.id,n1_0.text from book b1_0 left join note n1_0 on b1_0.id=n1_0.book_id where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [4]
|
||||
OptimisticLockException surfaced directly from the merge() call.
|
||||
exception: jakarta.persistence.OptimisticLockException: Row was already updated or deleted by another transaction for entity [com.ankurm.hibernatedemo.model.Book with id '4']
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.status,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [4]
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create table book (id bigint not null, author varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
Hibernate: create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create sequence book_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_seq start with 1 increment by 25
|
||||
Hibernate: select next value for book_seq
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.model.Book */insert into book (author,title,version,id) values (?,?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Robert C. Martin]
|
||||
binding parameter (2:VARCHAR) <- [Clean Code]
|
||||
binding parameter (3:BIGINT) <- [0]
|
||||
binding parameter (4:BIGINT) <- [1]
|
||||
SEED: inserted Book{id=1, title=Clean Code, author=Robert C. Martin, version=0}
|
||||
--- Step 1: load the row, then close the session (entity is now detached) ---
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
detached instance in hand: Book{id=1, title=Clean Code, author=Robert C. Martin, version=0}
|
||||
--- Step 2: a second, independent session edits the same row and commits ---
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
Hibernate: /* update for com.ankurm.hibernatedemo.model.Book */update book set author=?,title=?,version=? where id=? and version=?
|
||||
binding parameter (1:VARCHAR) <- [Robert C. Martin]
|
||||
binding parameter (2:VARCHAR) <- [Clean Code (2nd Edition)]
|
||||
binding parameter (3:BIGINT) <- [1]
|
||||
binding parameter (4:BIGINT) <- [1]
|
||||
binding parameter (5:BIGINT) <- [0]
|
||||
second session committed: Book{id=1, title=Clean Code (2nd Edition), author=Robert C. Martin, version=1} -- version column has now advanced in the database
|
||||
--- Step 3: mutate the ORIGINAL detached instance (still holding the OLD version) and merge() it ---
|
||||
detached instance before merge (note the version and title are both stale): Book{id=1, title=Clean Code, author=Robert C. Martin (Uncle Bob), version=0}
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
merge() threw jakarta.persistence.OptimisticLockException: Row was already updated or deleted by another transaction for entity [com.ankurm.hibernatedemo.model.Book with id '1']
|
||||
the title change from Step 2 survives untouched -- merge() refused to apply a write built on a stale version
|
||||
--- Step 4: refresh() on a MANAGED entity with an unflushed local edit ---
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
before refresh(): Book{id=1, title=Clean Code (2nd Edition), author=SOMEONE ELSE ENTIRELY (never flushed), version=1}
|
||||
Hibernate: select b1_0.id,b1_0.author,b1_0.title,b1_0.version from book b1_0 where b1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
after refresh(): Book{id=1, title=Clean Code (2nd Edition), author=Robert C. Martin, version=1} -- the local edit is gone, no exception was thrown
|
||||
@@ -0,0 +1,6 @@
|
||||
cacheable=true named query: puts after 1st run = 1, cache hits after 2nd run = 1
|
||||
Employee.byNativeDto(ACTIVE): [EmployeeDto{id=1, firstName=Native1}]
|
||||
JPQL constructor expression into a record: [EmployeeRecordDto[id=3, firstName=RecordTest]]
|
||||
Employee.findByName(Ankur): 1 rows
|
||||
getSingleResultOrNull() on zero rows returned: null
|
||||
getSingleResult() on zero rows threw: jakarta.persistence.NoResultException: No result found for query [SELECT e FROM NqEmployee e WHERE e.firstName = :n]
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
annotation-defined named query result: 1 rows
|
||||
orm.xml-defined named query result: 1 rows
|
||||
XmlQueryEmployee.overridden (annotation says salary<0, orm.xml says salary>:min): 1 rows
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
PERF (shared sandbox container, indicative only): 5000 iterations after 500 warmup each
|
||||
PERF named query : total=620.878923 ms, avg=124.17578459999999 us/call
|
||||
PERF inline JPQL : total=568.874652 ms, avg=113.7749304 us/call
|
||||
PERF ratio (named/inline) = 1.0914160453751416
|
||||
--- second run for consistency ---
|
||||
PERF (shared sandbox container, indicative only): 5000 iterations after 500 warmup each
|
||||
PERF named query : total=683.679163 ms, avg=136.73583259999998 us/call
|
||||
PERF inline JPQL : total=641.327846 ms, avg=128.26556920000002 us/call
|
||||
PERF ratio (named/inline) = 1.066036922089299
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
22:59:19.100 [main] INFO DEMO -- startup_check=false: SessionFactory built successfully with the broken named query still inside it: true
|
||||
22:59:19.332 [main] INFO DEMO -- startup_check=false: query only fails when actually CALLED -- class: java.lang.IllegalArgumentException, message: org.hibernate.query.sqm.UnknownPathException: Could not resolve attribute 'firsNam' of 'com.ankurm.brokenprobe.BrokenNamedQueryEmployee' [SELECT e FROM BrokenNamedQueryEmployee e WHERE e.firsNam = :name]
|
||||
22:59:19.367 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
22:59:19.373 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
--
|
||||
22:59:19.414 [main] INFO DEMO -- startup_check=true (default): bootstrap failure -- wrapper class: org.hibernate.query.NamedQueryValidationException
|
||||
22:59:19.414 [main] INFO DEMO -- startup_check=true (default): verbatim message: Errors in named queries:
|
||||
[1] Error in query named 'BrokenNamedQueryEmployee.badProperty': Could not resolve attribute 'firsNam' of 'com.ankurm.brokenprobe.BrokenNamedQueryEmployee' [SELECT e FROM BrokenNamedQueryEmployee e WHERE e.firsNam = :name]
|
||||
@@ -0,0 +1,15 @@
|
||||
$ javap -cp <hibernate-core-7.4.5.Final> org.hibernate.Session | grep -i naturalid
|
||||
public abstract <T> org.hibernate.NaturalIdLoadAccess<T> byNaturalId(java.lang.Class<T>);
|
||||
public abstract <T> org.hibernate.NaturalIdLoadAccess<T> byNaturalId(java.lang.String);
|
||||
public abstract <T> org.hibernate.SimpleNaturalIdLoadAccess<T> bySimpleNaturalId(java.lang.Class<T>);
|
||||
public abstract <T> org.hibernate.SimpleNaturalIdLoadAccess<T> bySimpleNaturalId(java.lang.String);
|
||||
public abstract <T> org.hibernate.NaturalIdMultiLoadAccess<T> byMultipleNaturalId(java.lang.Class<T>);
|
||||
public abstract <T> org.hibernate.NaturalIdMultiLoadAccess<T> byMultipleNaturalId(java.lang.String);
|
||||
|
||||
$ javap -cp <hibernate-core-7.4.5.Final> org.hibernate.annotations.TimeZoneStorageType # for comparison in ch.13
|
||||
public static final org.hibernate.annotations.TimeZoneStorageType NATIVE;
|
||||
public static final org.hibernate.annotations.TimeZoneStorageType NORMALIZE;
|
||||
public static final org.hibernate.annotations.TimeZoneStorageType NORMALIZE_UTC;
|
||||
public static final org.hibernate.annotations.TimeZoneStorageType COLUMN;
|
||||
public static final org.hibernate.annotations.TimeZoneStorageType AUTO;
|
||||
public static final org.hibernate.annotations.TimeZoneStorageType DEFAULT;
|
||||
Executable
+365
@@ -0,0 +1,365 @@
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/tmp/tools/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
23:06:11.225 [main] INFO org.hibernate.orm.core -- HHH000001: Hibernate ORM core version 7.4.5.Final
|
||||
23:06:11.265 [main] INFO org.hibernate.orm.cache -- HHH90001028: Second-level cache region factory [org.hibernate.cache.jcache.internal.JCacheRegionFactory]
|
||||
23:06:11.512 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:06:11.710 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:h2:mem:naturalidl2;DB_CLOSE_DELAY=-1]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Default catalog/schema: NATURALIDL2/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 100
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.ehcache.impl.internal.concurrent.ThreadLocalRandomUtil (file:/sessions/intelligent-loving-cori/.m2/repository/org/ehcache/ehcache/3.10.8/ehcache-3.10.8-jakarta.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class org.ehcache.impl.internal.concurrent.ThreadLocalRandomUtil
|
||||
WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release
|
||||
23:06:12.413 [main] WARN org.hibernate.orm.cache -- HHH90001006: Missing cache region [com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct] was created with provider-specific default policies. Explicitly configure the region and its policies, or disable this warning by setting 'hibernate.javax.cache.missing_cache_strategy' to 'create'.
|
||||
23:06:12.478 [main] INFO org.ehcache.core.EhcacheManager -- Cache 'com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct' created in EhcacheManager.
|
||||
23:06:12.489 [main] WARN org.hibernate.orm.cache -- HHH90001006: Missing cache region [com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct##NaturalId] was created with provider-specific default policies. Explicitly configure the region and its policies, or disable this warning by setting 'hibernate.javax.cache.missing_cache_strategy' to 'create'.
|
||||
23:06:12.492 [main] INFO org.ehcache.core.EhcacheManager -- Cache 'com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct##NaturalId' created in EhcacheManager.
|
||||
23:06:12.992 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
RESULT[naturalid-l2-cache-real-miss-then-hit]: first lookup (genuine cold row) queries=1, naturalId miss=1, naturalId put=1 | second lookup (new session) cumulative queries=1, naturalId hits=1
|
||||
23:06:13.193 [main] INFO org.ehcache.core.EhcacheManager -- Cache 'com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct##NaturalId' removed from EhcacheManager.
|
||||
23:06:13.194 [main] INFO org.ehcache.core.EhcacheManager -- Cache 'com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct' removed from EhcacheManager.
|
||||
23:06:13.218 [main] INFO org.hibernate.orm.cache -- HHH90001028: Second-level cache region factory [org.hibernate.cache.jcache.internal.JCacheRegionFactory]
|
||||
23:06:13.257 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:06:13.263 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:h2:mem:naturalidl2;DB_CLOSE_DELAY=-1]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Default catalog/schema: NATURALIDL2/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 100
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
23:06:13.306 [main] WARN org.hibernate.orm.cache -- HHH90001006: Missing cache region [com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct] was created with provider-specific default policies. Explicitly configure the region and its policies, or disable this warning by setting 'hibernate.javax.cache.missing_cache_strategy' to 'create'.
|
||||
23:06:13.310 [main] INFO org.ehcache.core.EhcacheManager -- Cache 'com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct' created in EhcacheManager.
|
||||
23:06:13.311 [main] WARN org.hibernate.orm.cache -- HHH90001006: Missing cache region [com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct##NaturalId] was created with provider-specific default policies. Explicitly configure the region and its policies, or disable this warning by setting 'hibernate.javax.cache.missing_cache_strategy' to 'create'.
|
||||
23:06:13.323 [main] INFO org.ehcache.core.EhcacheManager -- Cache 'com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct##NaturalId' created in EhcacheManager.
|
||||
23:06:13.335 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
RESULT[naturalid-l2-cache]: immediately after persist()+commit(): queries=2, naturalId cache put=1, naturalId cache hit=0 -- @NaturalIdCache populates the L2 region on INSERT, before anyone ever looked it up.
|
||||
RESULT[naturalid-l2-cache]: session1 (post-insert) cumulative queries=0 | session2 (new session, same natural id) cumulative queries=0, naturalId cache hits=2
|
||||
23:06:13.375 [main] INFO org.ehcache.core.EhcacheManager -- Cache 'com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct##NaturalId' removed from EhcacheManager.
|
||||
23:06:13.375 [main] INFO org.ehcache.core.EhcacheManager -- Cache 'com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct' removed from EhcacheManager.
|
||||
HHH90000033: Encountered use of deprecated annotation [interface jakarta.persistence.Temporal] at com.ankurm.hibernatedemo.persistenceannotations.TemporalOnJavaTimeEntity.eventDate.
|
||||
HHH90001006: Missing cache region [com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct##NaturalId] was created with provider-specific default policies. Explicitly configure the region and its policies, or disable this warning by setting 'hibernate.javax.cache.missing_cache_strategy' to 'create'.
|
||||
HHH90001006: Missing cache region [com.ankurm.hibernatedemo.naturalid.CachedNaturalIdProduct] was created with provider-specific default policies. Explicitly configure the region and its policies, or disable this warning by setting 'hibernate.javax.cache.missing_cache_strategy' to 'create'.
|
||||
create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_natural_id_product(rn_ integer not null, id bigint, name varchar(255), sku varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_natural_id_product(rn_ integer not null, id bigint, name varchar(255), sku varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_identity_hash_set_entity(rn_ integer not null, id bigint, label varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_identity_hash_set_entity(rn_ integer not null, id bigint, label varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_cached_natural_id_product(rn_ integer not null, id bigint, name varchar(255), sku varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_cached_natural_id_product(rn_ integer not null, id bigint, name varchar(255), sku varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_mixed_access_entity(rn_ integer not null, id bigint, computedLabel varchar(255), rawValue varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_mixed_access_entity(rn_ integer not null, id bigint, computedLabel varchar(255), rawValue varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_json_column_entity(rn_ integer not null, id bigint, details json, primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_json_column_entity(rn_ integer not null, id bigint, details json, primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_temporal_on_java_time_entity(eventDate date, rn_ integer not null, id bigint, primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_temporal_on_java_time_entity(eventDate date, rn_ integer not null, id bigint, primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_company(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_company(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_immutable_natural_id_entity(rn_ integer not null, id bigint, code varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_immutable_natural_id_entity(rn_ integer not null, id bigint, code varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_natural_id_equals_entity(rn_ integer not null, id bigint, name varchar(255), sku varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_natural_id_equals_entity(rn_ integer not null, id bigint, name varchar(255), sku varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_department(rn_ integer not null, company_id bigint, id bigint, deptCode varchar(255), name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_department(rn_ integer not null, company_id bigint, id bigint, deptCode varchar(255), name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_enumerated_value_entity(rn_ integer not null, id bigint, priority varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_enumerated_value_entity(rn_ integer not null, id bigint, priority varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_mutable_natural_id_entity(rn_ integer not null, id bigint, code varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_mutable_natural_id_entity(rn_ integer not null, id bigint, code varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_id_based_equals_entity(rn_ integer not null, id bigint, label varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_id_based_equals_entity(rn_ integer not null, id bigint, label varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_override_entity(rn_ integer not null, id bigint, value varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_override_entity(rn_ integer not null, id bigint, value varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_enum_default_ordinal_entity(rn_ integer not null, status tinyint, id bigint, primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_enum_default_ordinal_entity(rn_ integer not null, status tinyint, id bigint, primary key (rn_)) transactional
|
||||
create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
Hibernate: create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
create table cached_natural_id_product (id bigint not null, name varchar(255), sku varchar(255) not null, primary key (id))
|
||||
Hibernate: create table cached_natural_id_product (id bigint not null, name varchar(255), sku varchar(255) not null, primary key (id))
|
||||
create table company (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table company (id bigint not null, name varchar(255), primary key (id))
|
||||
create table department (id bigint not null, dept_code varchar(255), name varchar(255), company_id bigint, primary key (id))
|
||||
Hibernate: create table department (id bigint not null, dept_code varchar(255), name varchar(255), company_id bigint, primary key (id))
|
||||
create table enum_default_ordinal_entity (id bigint not null, status tinyint check ((status between 0 and 2)), primary key (id))
|
||||
Hibernate: create table enum_default_ordinal_entity (id bigint not null, status tinyint check ((status between 0 and 2)), primary key (id))
|
||||
create table enumerated_value_entity (id bigint not null, priority varchar(255) check ((priority in ('H','L','M'))), primary key (id))
|
||||
Hibernate: create table enumerated_value_entity (id bigint not null, priority varchar(255) check ((priority in ('H','L','M'))), primary key (id))
|
||||
create table id_based_equals_entity (id bigint not null, label varchar(255), primary key (id))
|
||||
Hibernate: create table id_based_equals_entity (id bigint not null, label varchar(255), primary key (id))
|
||||
create table identity_hash_set_entity (id bigint not null, label varchar(255), primary key (id))
|
||||
Hibernate: create table identity_hash_set_entity (id bigint not null, label varchar(255), primary key (id))
|
||||
create table immutable_natural_id_entity (id bigint not null, code varchar(255), primary key (id))
|
||||
Hibernate: create table immutable_natural_id_entity (id bigint not null, code varchar(255), primary key (id))
|
||||
create table json_column_entity (id bigint not null, details json, primary key (id))
|
||||
Hibernate: create table json_column_entity (id bigint not null, details json, primary key (id))
|
||||
create table mixed_access_entity (id bigint not null, computed_label varchar(255), raw_value varchar(255), primary key (id))
|
||||
Hibernate: create table mixed_access_entity (id bigint not null, computed_label varchar(255), raw_value varchar(255), primary key (id))
|
||||
create table mutable_natural_id_entity (id bigint not null, code varchar(255), primary key (id))
|
||||
Hibernate: create table mutable_natural_id_entity (id bigint not null, code varchar(255), primary key (id))
|
||||
create table natural_id_equals_entity (id bigint not null, name varchar(255), sku varchar(255) not null, primary key (id))
|
||||
Hibernate: create table natural_id_equals_entity (id bigint not null, name varchar(255), sku varchar(255) not null, primary key (id))
|
||||
create table natural_id_product (id bigint not null, name varchar(255), sku varchar(255) not null, primary key (id))
|
||||
Hibernate: create table natural_id_product (id bigint not null, name varchar(255), sku varchar(255) not null, primary key (id))
|
||||
create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
Hibernate: create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
create table override_entity (id bigint not null, annotation_name varchar(255), primary key (id))
|
||||
Hibernate: create table override_entity (id bigint not null, annotation_name varchar(255), primary key (id))
|
||||
create table temporal_on_java_time_entity (id bigint not null, event_date date, primary key (id))
|
||||
Hibernate: create table temporal_on_java_time_entity (id bigint not null, event_date date, primary key (id))
|
||||
create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
alter table if exists cached_natural_id_product drop constraint if exists UKje04jryb5drgla4ee8f9wb09h
|
||||
Hibernate: alter table if exists cached_natural_id_product drop constraint if exists UKje04jryb5drgla4ee8f9wb09h
|
||||
alter table if exists cached_natural_id_product add constraint UKje04jryb5drgla4ee8f9wb09h unique (sku)
|
||||
Hibernate: alter table if exists cached_natural_id_product add constraint UKje04jryb5drgla4ee8f9wb09h unique (sku)
|
||||
alter table if exists department drop constraint if exists UKshij4bp4ym2hmov81mkrwn0c8
|
||||
Hibernate: alter table if exists department drop constraint if exists UKshij4bp4ym2hmov81mkrwn0c8
|
||||
alter table if exists department add constraint UKshij4bp4ym2hmov81mkrwn0c8 unique (company_id, dept_code)
|
||||
Hibernate: alter table if exists department add constraint UKshij4bp4ym2hmov81mkrwn0c8 unique (company_id, dept_code)
|
||||
alter table if exists immutable_natural_id_entity drop constraint if exists UK5gvhgvwmwj20jj1uh486alunu
|
||||
Hibernate: alter table if exists immutable_natural_id_entity drop constraint if exists UK5gvhgvwmwj20jj1uh486alunu
|
||||
alter table if exists immutable_natural_id_entity add constraint UK5gvhgvwmwj20jj1uh486alunu unique (code)
|
||||
Hibernate: alter table if exists immutable_natural_id_entity add constraint UK5gvhgvwmwj20jj1uh486alunu unique (code)
|
||||
alter table if exists mutable_natural_id_entity drop constraint if exists UK27w8jwneoik5sx2gt8q9rduf5
|
||||
Hibernate: alter table if exists mutable_natural_id_entity drop constraint if exists UK27w8jwneoik5sx2gt8q9rduf5
|
||||
alter table if exists mutable_natural_id_entity add constraint UK27w8jwneoik5sx2gt8q9rduf5 unique (code)
|
||||
Hibernate: alter table if exists mutable_natural_id_entity add constraint UK27w8jwneoik5sx2gt8q9rduf5 unique (code)
|
||||
alter table if exists natural_id_equals_entity drop constraint if exists UKs5mlj556xgu0u0dl8jq93xvi1
|
||||
Hibernate: alter table if exists natural_id_equals_entity drop constraint if exists UKs5mlj556xgu0u0dl8jq93xvi1
|
||||
alter table if exists natural_id_equals_entity add constraint UKs5mlj556xgu0u0dl8jq93xvi1 unique (sku)
|
||||
Hibernate: alter table if exists natural_id_equals_entity add constraint UKs5mlj556xgu0u0dl8jq93xvi1 unique (sku)
|
||||
alter table if exists natural_id_product drop constraint if exists UK4uilk3eo365mgcetnh0da4n3b
|
||||
Hibernate: alter table if exists natural_id_product drop constraint if exists UK4uilk3eo365mgcetnh0da4n3b
|
||||
alter table if exists natural_id_product add constraint UK4uilk3eo365mgcetnh0da4n3b unique (sku)
|
||||
Hibernate: alter table if exists natural_id_product add constraint UK4uilk3eo365mgcetnh0da4n3b unique (sku)
|
||||
create sequence book_seq start with 1 increment by 50
|
||||
Hibernate: create sequence book_seq start with 1 increment by 50
|
||||
create sequence cached_natural_id_product_seq start with 1 increment by 50
|
||||
Hibernate: create sequence cached_natural_id_product_seq start with 1 increment by 50
|
||||
create sequence company_seq start with 1 increment by 50
|
||||
Hibernate: create sequence company_seq start with 1 increment by 50
|
||||
create sequence department_seq start with 1 increment by 50
|
||||
Hibernate: create sequence department_seq start with 1 increment by 50
|
||||
create sequence enum_default_ordinal_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence enum_default_ordinal_entity_seq start with 1 increment by 50
|
||||
create sequence enumerated_value_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence enumerated_value_entity_seq start with 1 increment by 50
|
||||
create sequence id_based_equals_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence id_based_equals_entity_seq start with 1 increment by 50
|
||||
create sequence identity_hash_set_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence identity_hash_set_entity_seq start with 1 increment by 50
|
||||
create sequence immutable_natural_id_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence immutable_natural_id_entity_seq start with 1 increment by 50
|
||||
create sequence json_column_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence json_column_entity_seq start with 1 increment by 50
|
||||
create sequence mixed_access_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence mixed_access_entity_seq start with 1 increment by 50
|
||||
create sequence mutable_natural_id_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence mutable_natural_id_entity_seq start with 1 increment by 50
|
||||
create sequence natural_id_equals_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence natural_id_equals_entity_seq start with 1 increment by 50
|
||||
create sequence natural_id_product_seq start with 1 increment by 50
|
||||
Hibernate: create sequence natural_id_product_seq start with 1 increment by 50
|
||||
create sequence override_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence override_entity_seq start with 1 increment by 50
|
||||
create sequence temporal_on_java_time_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence temporal_on_java_time_entity_seq start with 1 increment by 50
|
||||
create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
Hibernate: create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
Hibernate: create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
create sequence widget_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_seq start with 1 increment by 25
|
||||
alter table if exists department add constraint FKh1m88q0f7sc0mk76kju4kcn6f foreign key (company_id) references company
|
||||
Hibernate: alter table if exists department add constraint FKh1m88q0f7sc0mk76kju4kcn6f foreign key (company_id) references company
|
||||
alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
Hibernate: alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build as described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html#0.3
|
||||
WARNING: A Java agent has been loaded dynamically (/sessions/intelligent-loving-cori/.m2/repository/net/bytebuddy/byte-buddy-agent/1.18.11/byte-buddy-agent-1.18.11.jar)
|
||||
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
|
||||
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
|
||||
WARNING: Dynamic loading of agents will be disallowed by default in a future release
|
||||
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
|
||||
select next value for company_seq
|
||||
Hibernate: select next value for company_seq
|
||||
select next value for company_seq
|
||||
Hibernate: select next value for company_seq
|
||||
select next value for department_seq
|
||||
Hibernate: select next value for department_seq
|
||||
select next value for department_seq
|
||||
Hibernate: select next value for department_seq
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.Company */insert into company (name,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.Company */insert into company (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [Acme]
|
||||
binding parameter (2:BIGINT) <- [1]
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.Company */insert into company (name,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.Company */insert into company (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [Other Co]
|
||||
binding parameter (2:BIGINT) <- [2]
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.Department */insert into department (company_id,dept_code,name,id) values (?,?,?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.Department */insert into department (company_id,dept_code,name,id) values (?,?,?,?)
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
binding parameter (2:VARCHAR) <- [ENG-01]
|
||||
binding parameter (3:VARCHAR) <- [Acme Engineering]
|
||||
binding parameter (4:BIGINT) <- [1]
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.Department */insert into department (company_id,dept_code,name,id) values (?,?,?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.Department */insert into department (company_id,dept_code,name,id) values (?,?,?,?)
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
binding parameter (2:VARCHAR) <- [ENG-01]
|
||||
binding parameter (3:VARCHAR) <- [Other Co Engineering]
|
||||
binding parameter (4:BIGINT) <- [2]
|
||||
select d1_0.id,c1_0.id,c1_0.name,d1_0.dept_code,d1_0.name from department d1_0 left join company c1_0 on c1_0.id=d1_0.company_id where d1_0.company_id=? and d1_0.dept_code=?
|
||||
Hibernate: select d1_0.id,c1_0.id,c1_0.name,d1_0.dept_code,d1_0.name from department d1_0 left join company c1_0 on c1_0.id=d1_0.company_id where d1_0.company_id=? and d1_0.dept_code=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
binding parameter (2:VARCHAR) <- [ENG-01]
|
||||
RESULT[composite-naturalid]: byNaturalId(company=Acme, deptCode=ENG-01) resolved to 'Acme Engineering' in 1 query/queries
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.Company */insert into company (name,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.Company */insert into company (name,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [SQL-Capture Co]
|
||||
binding parameter (2:BIGINT) <- [3]
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.Department */insert into department (company_id,dept_code,name,id) values (?,?,?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.Department */insert into department (company_id,dept_code,name,id) values (?,?,?,?)
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
binding parameter (2:VARCHAR) <- [OPS-1]
|
||||
binding parameter (3:VARCHAR) <- [Operations]
|
||||
binding parameter (4:BIGINT) <- [3]
|
||||
select d1_0.id,c1_0.id,c1_0.name,d1_0.dept_code,d1_0.name from department d1_0 left join company c1_0 on c1_0.id=d1_0.company_id where d1_0.company_id=? and d1_0.dept_code=?
|
||||
Hibernate: select d1_0.id,c1_0.id,c1_0.name,d1_0.dept_code,d1_0.name from department d1_0 left join company c1_0 on c1_0.id=d1_0.company_id where d1_0.company_id=? and d1_0.dept_code=?
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
binding parameter (2:VARCHAR) <- [OPS-1]
|
||||
select next value for mutable_natural_id_entity_seq
|
||||
Hibernate: select next value for mutable_natural_id_entity_seq
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.MutableNaturalIdEntity */insert into mutable_natural_id_entity (code,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.MutableNaturalIdEntity */insert into mutable_natural_id_entity (code,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [CODE-X]
|
||||
binding parameter (2:BIGINT) <- [1]
|
||||
select mnie1_0.id,mnie1_0.code from mutable_natural_id_entity mnie1_0 where mnie1_0.id=?
|
||||
Hibernate: select mnie1_0.id,mnie1_0.code from mutable_natural_id_entity mnie1_0 where mnie1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
/* update for com.ankurm.hibernatedemo.naturalid.MutableNaturalIdEntity */update mutable_natural_id_entity set code=? where id=?
|
||||
Hibernate: /* update for com.ankurm.hibernatedemo.naturalid.MutableNaturalIdEntity */update mutable_natural_id_entity set code=? where id=?
|
||||
binding parameter (1:VARCHAR) <- [CODE-Y]
|
||||
binding parameter (2:BIGINT) <- [1]
|
||||
/* dynamic native SQL query */ select code from mutable_natural_id_entity where id = 1
|
||||
Hibernate: /* dynamic native SQL query */ select code from mutable_natural_id_entity where id = 1
|
||||
RESULT[naturalid-mutable-mutation]: flush succeeded, DB column now = CODE-Y
|
||||
select next value for mutable_natural_id_entity_seq
|
||||
Hibernate: select next value for mutable_natural_id_entity_seq
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.MutableNaturalIdEntity */insert into mutable_natural_id_entity (code,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.MutableNaturalIdEntity */insert into mutable_natural_id_entity (code,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [CODE-OLD]
|
||||
binding parameter (2:BIGINT) <- [2]
|
||||
select mnie1_0.id,mnie1_0.code from mutable_natural_id_entity mnie1_0 where mnie1_0.id=?
|
||||
Hibernate: select mnie1_0.id,mnie1_0.code from mutable_natural_id_entity mnie1_0 where mnie1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
/* update for com.ankurm.hibernatedemo.naturalid.MutableNaturalIdEntity */update mutable_natural_id_entity set code=? where id=?
|
||||
Hibernate: /* update for com.ankurm.hibernatedemo.naturalid.MutableNaturalIdEntity */update mutable_natural_id_entity set code=? where id=?
|
||||
binding parameter (1:VARCHAR) <- [CODE-NEW]
|
||||
binding parameter (2:BIGINT) <- [2]
|
||||
select mnie1_0.id,mnie1_0.code from mutable_natural_id_entity mnie1_0 where mnie1_0.code=?
|
||||
Hibernate: select mnie1_0.id,mnie1_0.code from mutable_natural_id_entity mnie1_0 where mnie1_0.code=?
|
||||
binding parameter (1:VARCHAR) <- [CODE-OLD]
|
||||
select mnie1_0.id,mnie1_0.code from mutable_natural_id_entity mnie1_0 where mnie1_0.code=?
|
||||
Hibernate: select mnie1_0.id,mnie1_0.code from mutable_natural_id_entity mnie1_0 where mnie1_0.code=?
|
||||
binding parameter (1:VARCHAR) <- [CODE-NEW]
|
||||
RESULT[naturalid-mutable-stale-lookup]: byNaturalId("CODE-OLD") = null, byNaturalId("CODE-NEW") = 2
|
||||
select next value for immutable_natural_id_entity_seq
|
||||
Hibernate: select next value for immutable_natural_id_entity_seq
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.ImmutableNaturalIdEntity */insert into immutable_natural_id_entity (code,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.ImmutableNaturalIdEntity */insert into immutable_natural_id_entity (code,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [CODE-A]
|
||||
binding parameter (2:BIGINT) <- [1]
|
||||
select inie1_0.id,inie1_0.code from immutable_natural_id_entity inie1_0 where inie1_0.id=?
|
||||
Hibernate: select inie1_0.id,inie1_0.code from immutable_natural_id_entity inie1_0 where inie1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
RESULT[naturalid-immutable-mutation]: flushing a changed IMMUTABLE natural id threw: org.hibernate.HibernateException: An immutable natural identifier of entity com.ankurm.hibernatedemo.naturalid.ImmutableNaturalIdEntity was altered from `CODE-A` to `CODE-B`
|
||||
select next value for natural_id_product_seq
|
||||
Hibernate: select next value for natural_id_product_seq
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.NaturalIdProduct */insert into natural_id_product (name,sku,id) values (?,?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.NaturalIdProduct */insert into natural_id_product (name,sku,id) values (?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Widget]
|
||||
binding parameter (2:VARCHAR) <- [SKU-L1-1]
|
||||
binding parameter (3:BIGINT) <- [1]
|
||||
select nip1_0.id,nip1_0.name,nip1_0.sku from natural_id_product nip1_0 where nip1_0.sku=?
|
||||
Hibernate: select nip1_0.id,nip1_0.name,nip1_0.sku from natural_id_product nip1_0 where nip1_0.sku=?
|
||||
binding parameter (1:VARCHAR) <- [SKU-L1-1]
|
||||
RESULT[naturalid-l1-no-l2]: queries after 1st bySimpleNaturalId=1, after 2nd (same session)=1 (no @NaturalIdCache, no L2 cache provider configured)
|
||||
select next value for natural_id_product_seq
|
||||
Hibernate: select next value for natural_id_product_seq
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.NaturalIdProduct */insert into natural_id_product (name,sku,id) values (?,?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.NaturalIdProduct */insert into natural_id_product (name,sku,id) values (?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [Gadget]
|
||||
binding parameter (2:VARCHAR) <- [SKU-L1-2]
|
||||
binding parameter (3:BIGINT) <- [2]
|
||||
select nip1_0.id,nip1_0.name,nip1_0.sku from natural_id_product nip1_0 where nip1_0.sku=?
|
||||
Hibernate: select nip1_0.id,nip1_0.name,nip1_0.sku from natural_id_product nip1_0 where nip1_0.sku=?
|
||||
binding parameter (1:VARCHAR) <- [SKU-L1-2]
|
||||
select nip1_0.id,nip1_0.name,nip1_0.sku from natural_id_product nip1_0 where nip1_0.sku=?
|
||||
Hibernate: select nip1_0.id,nip1_0.name,nip1_0.sku from natural_id_product nip1_0 where nip1_0.sku=?
|
||||
binding parameter (1:VARCHAR) <- [SKU-L1-2]
|
||||
RESULT[naturalid-cross-session-no-l2]: queries after session 1 lookup=1, cumulative after a NEW session repeats the same lookup=2 (no L2 cache -- the L1 natural-id map dies with the session)
|
||||
select next value for natural_id_equals_entity_seq
|
||||
Hibernate: select next value for natural_id_equals_entity_seq
|
||||
/* insert for com.ankurm.hibernatedemo.naturalid.NaturalIdEqualsEntity */insert into natural_id_equals_entity (name,sku,id) values (?,?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.naturalid.NaturalIdEqualsEntity */insert into natural_id_equals_entity (name,sku,id) values (?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [widget]
|
||||
binding parameter (2:VARCHAR) <- [SKU-EQ-1]
|
||||
binding parameter (3:BIGINT) <- [1]
|
||||
RESULT[naturalid-equals-hashset]: after persist(), e.getId()=1, e.getSku()=SKU-EQ-1, set.contains(e) = true (equals/hashCode based on the immutable natural id, NOT the surrogate id)
|
||||
RESULT[naturalid-equals-transient-dup]: a.equals(b)=true for two transient instances sharing sku='SKU-EQ-DUP' but different names; HashSet.add(b) rejected it as a duplicate = true
|
||||
RESULT[naturalid-equals-transient]: a.equals(b) for two DIFFERENT transient instances = false (both have null surrogate ids, but different natural ids)
|
||||
@@ -0,0 +1,17 @@
|
||||
@JdbcTypeCode(SqlTypes.JSON) with NO JSON provider on the classpath.
|
||||
|
||||
Reproduced by removing tools.jackson.core:jackson-databind and excluding
|
||||
spring-boot-starter-jackson from spring-boot-starter-web, leaving zero JSON
|
||||
providers on the test classpath:
|
||||
|
||||
$ mvn -o -B dependency:list -DincludeScope=test | grep -icE 'jackson-databind|yasson|johnzon'
|
||||
0
|
||||
|
||||
$ mvn -o -B test -Dtest=JsonColumnOnH2Test
|
||||
org.hibernate.HibernateException: Could not find a FormatMapper for the JSON format, which is required for mapping JSON types. JSON FormatMapper configuration is automatic, but requires that you have either Jackson or a JSONB implementation like Yasson on the class path.
|
||||
|
||||
Put either Jackson or a JSONB implementation back on the classpath and the same
|
||||
test passes. spring-boot-starter-data-jpa on its own does not bring one:
|
||||
|
||||
$ mvn -o -B test -Dtest=JsonColumnOnH2Test # with tools.jackson.core:jackson-databind present
|
||||
[INFO] BUILD SUCCESS
|
||||
Executable
+208
@@ -0,0 +1,208 @@
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/tmp/tools/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
HHH90000033: Encountered use of deprecated annotation [interface jakarta.persistence.Temporal] at com.ankurm.hibernatedemo.persistenceannotations.TemporalOnLocalDateEntity.eventDate.
|
||||
create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_identity_hash_set_entity(rn_ integer not null, id bigint, label varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_identity_hash_set_entity(rn_ integer not null, id bigint, label varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_mixed_access_entity(rn_ integer not null, id bigint, computedLabel varchar(255), rawValue varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_mixed_access_entity(rn_ integer not null, id bigint, computedLabel varchar(255), rawValue varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_enumerated_value_entity(rn_ integer not null, id bigint, priority varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_enumerated_value_entity(rn_ integer not null, id bigint, priority varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_json_column_entity(rn_ integer not null, id bigint, details json, primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_json_column_entity(rn_ integer not null, id bigint, details json, primary key (rn_)) transactional
|
||||
create global temporary table HTE_id_based_equals_entity(rn_ integer not null, id bigint, label varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_id_based_equals_entity(rn_ integer not null, id bigint, label varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_override_entity(rn_ integer not null, id bigint, value varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_override_entity(rn_ integer not null, id bigint, value varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_enum_default_ordinal_entity(rn_ integer not null, status tinyint, id bigint, primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_enum_default_ordinal_entity(rn_ integer not null, status tinyint, id bigint, primary key (rn_)) transactional
|
||||
create global temporary table HTE_temporal_on_java_time_entity(eventDate date, rn_ integer not null, id bigint, primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_temporal_on_java_time_entity(eventDate date, rn_ integer not null, id bigint, primary key (rn_)) transactional
|
||||
create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
Hibernate: create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
create table enum_default_ordinal_entity (id bigint not null, status tinyint check ((status between 0 and 2)), primary key (id))
|
||||
Hibernate: create table enum_default_ordinal_entity (id bigint not null, status tinyint check ((status between 0 and 2)), primary key (id))
|
||||
create table enumerated_value_entity (id bigint not null, priority varchar(255) check ((priority in ('H','L','M'))), primary key (id))
|
||||
Hibernate: create table enumerated_value_entity (id bigint not null, priority varchar(255) check ((priority in ('H','L','M'))), primary key (id))
|
||||
create table id_based_equals_entity (id bigint not null, label varchar(255), primary key (id))
|
||||
Hibernate: create table id_based_equals_entity (id bigint not null, label varchar(255), primary key (id))
|
||||
create table identity_hash_set_entity (id bigint not null, label varchar(255), primary key (id))
|
||||
Hibernate: create table identity_hash_set_entity (id bigint not null, label varchar(255), primary key (id))
|
||||
create table json_column_entity (id bigint not null, details json, primary key (id))
|
||||
Hibernate: create table json_column_entity (id bigint not null, details json, primary key (id))
|
||||
create table mixed_access_entity (id bigint not null, computed_label varchar(255), raw_value varchar(255), primary key (id))
|
||||
Hibernate: create table mixed_access_entity (id bigint not null, computed_label varchar(255), raw_value varchar(255), primary key (id))
|
||||
create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
Hibernate: create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
create table override_entity (id bigint not null, annotation_name varchar(255), primary key (id))
|
||||
Hibernate: create table override_entity (id bigint not null, annotation_name varchar(255), primary key (id))
|
||||
create table temporal_on_java_time_entity (id bigint not null, event_date date, primary key (id))
|
||||
Hibernate: create table temporal_on_java_time_entity (id bigint not null, event_date date, primary key (id))
|
||||
create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
create sequence book_seq start with 1 increment by 50
|
||||
Hibernate: create sequence book_seq start with 1 increment by 50
|
||||
create sequence enum_default_ordinal_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence enum_default_ordinal_entity_seq start with 1 increment by 50
|
||||
create sequence enumerated_value_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence enumerated_value_entity_seq start with 1 increment by 50
|
||||
create sequence id_based_equals_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence id_based_equals_entity_seq start with 1 increment by 50
|
||||
create sequence identity_hash_set_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence identity_hash_set_entity_seq start with 1 increment by 50
|
||||
create sequence json_column_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence json_column_entity_seq start with 1 increment by 50
|
||||
create sequence mixed_access_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence mixed_access_entity_seq start with 1 increment by 50
|
||||
create sequence override_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence override_entity_seq start with 1 increment by 50
|
||||
create sequence temporal_on_java_time_entity_seq start with 1 increment by 50
|
||||
Hibernate: create sequence temporal_on_java_time_entity_seq start with 1 increment by 50
|
||||
create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
Hibernate: create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
Hibernate: create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
create sequence widget_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_seq start with 1 increment by 25
|
||||
alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
Hibernate: alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build as described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html#0.3
|
||||
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
|
||||
WARNING: A Java agent has been loaded dynamically (/sessions/intelligent-loving-cori/.m2/repository/net/bytebuddy/byte-buddy-agent/1.18.11/byte-buddy-agent-1.18.11.jar)
|
||||
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
|
||||
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
|
||||
WARNING: Dynamic loading of agents will be disallowed by default in a future release
|
||||
select next value for id_based_equals_entity_seq
|
||||
Hibernate: select next value for id_based_equals_entity_seq
|
||||
/* insert for com.ankurm.hibernatedemo.persistenceannotations.IdBasedEqualsEntity */insert into id_based_equals_entity (label,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.persistenceannotations.IdBasedEqualsEntity */insert into id_based_equals_entity (label,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [widget]
|
||||
binding parameter (2:BIGINT) <- [1]
|
||||
RESULT[id-based-equals-hashset-trap]: after persist(), e.getId()=1, set.contains(e) = false (same reference, same set, only the hash code changed)
|
||||
RESULT[id-based-equals-hashset-trap]: manual iteration foundByIteration = true -- confirms equals() itself still works; it's HashSet's bucket indexing that is now wrong.
|
||||
select next value for mixed_access_entity_seq
|
||||
Hibernate: select next value for mixed_access_entity_seq
|
||||
/* insert for com.ankurm.hibernatedemo.persistenceannotations.MixedAccessEntity */insert into mixed_access_entity (computed_label,raw_value,id) values (?,?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.persistenceannotations.MixedAccessEntity */insert into mixed_access_entity (computed_label,raw_value,id) values (?,?,?)
|
||||
binding parameter (1:VARCHAR) <- [WIDGET]
|
||||
binding parameter (2:VARCHAR) <- [widget]
|
||||
binding parameter (3:BIGINT) <- [1]
|
||||
RESULT[mixed-access]: getComputedLabel() call count before persist=0, after commit/flush=2 (PROPERTY-access attributes are read via the getter at flush time, not via a backing field)
|
||||
/* dynamic native SQL query */ select computed_label from mixed_access_entity where id = 1
|
||||
Hibernate: /* dynamic native SQL query */ select computed_label from mixed_access_entity where id = 1
|
||||
RESULT[mixed-access]: DB column computed_label = WIDGET
|
||||
select next value for temporal_on_java_time_entity_seq
|
||||
Hibernate: select next value for temporal_on_java_time_entity_seq
|
||||
/* insert for com.ankurm.hibernatedemo.persistenceannotations.TemporalOnLocalDateEntity */insert into temporal_on_java_time_entity (event_date,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.persistenceannotations.TemporalOnLocalDateEntity */insert into temporal_on_java_time_entity (event_date,id) values (?,?)
|
||||
binding parameter (1:DATE) <- [2026-01-15]
|
||||
binding parameter (2:BIGINT) <- [1]
|
||||
select tojte1_0.id,tojte1_0.event_date from temporal_on_java_time_entity tojte1_0 where tojte1_0.id=?
|
||||
Hibernate: select tojte1_0.id,tojte1_0.event_date from temporal_on_java_time_entity tojte1_0 where tojte1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
RESULT[temporal-on-localdate]: boot succeeded (not silent -- Hibernate logs HHH90000033: Encountered use of deprecated annotation [interface jakarta.persistence.Temporal] at boot time, WARN level, one line per annotated field); round-tripped eventDate=2026-01-15. The mapping itself is unaffected -- LocalDate maps the same with or without @Temporal.
|
||||
HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
create global temporary table HTE_enum_default_ordinal_entity(rn_ integer not null, status tinyint, id bigint, primary key (rn_)) transactional
|
||||
drop table if exists enum_default_ordinal_entity cascade
|
||||
drop sequence if exists enum_default_ordinal_entity_SEQ
|
||||
create sequence enum_default_ordinal_entity_SEQ start with 1 increment by 50
|
||||
create table enum_default_ordinal_entity (status tinyint check ((status between 0 and 2)), id bigint not null, primary key (id))
|
||||
select next value for enum_default_ordinal_entity_SEQ
|
||||
insert into enum_default_ordinal_entity (status,id) values (?,?)
|
||||
binding parameter (1:TINYINT) <- [SHIPPED]
|
||||
binding parameter (2:BIGINT) <- [1]
|
||||
select status from enum_default_ordinal_entity where id = 1
|
||||
RESULT[enum-ordinal-default]: stored ordinal for SHIPPED (V1 ordering) = 1
|
||||
HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
select erve1_0.id,erve1_0.status from enum_default_ordinal_entity erve1_0 where erve1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
RESULT[enum-ordinal-default]: same row re-read through V2 (PENDING_REVIEW inserted before SHIPPED) enum ordering = PENDING_REVIEW -- no exception thrown, silently resolves to the WRONG constant.
|
||||
select next value for json_column_entity_seq
|
||||
Hibernate: select next value for json_column_entity_seq
|
||||
/* insert for com.ankurm.hibernatedemo.persistenceannotations.JsonColumnEntity */insert into json_column_entity (details,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.persistenceannotations.JsonColumnEntity */insert into json_column_entity (details,id) values (?,?)
|
||||
binding parameter (1:JSON) <- [{color=red, qty=5}]
|
||||
binding parameter (2:BIGINT) <- [1]
|
||||
select jce1_0.id,jce1_0.details from json_column_entity jce1_0 where jce1_0.id=?
|
||||
Hibernate: select jce1_0.id,jce1_0.details from json_column_entity jce1_0 where jce1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
RESULT[jdbctypecode-json-h2]: persisted+loaded details={color=red, qty=5}
|
||||
/* dynamic native SQL query */ select data_type from information_schema.columns where table_name = 'JSON_COLUMN_ENTITY' and column_name = 'DETAILS'
|
||||
Hibernate: /* dynamic native SQL query */ select data_type from information_schema.columns where table_name = 'JSON_COLUMN_ENTITY' and column_name = 'DETAILS'
|
||||
RESULT[jdbctypecode-json-h2]: H2 column type for the JSON field = JSON
|
||||
select next value for enumerated_value_entity_seq
|
||||
Hibernate: select next value for enumerated_value_entity_seq
|
||||
select next value for enumerated_value_entity_seq
|
||||
Hibernate: select next value for enumerated_value_entity_seq
|
||||
/* insert for com.ankurm.hibernatedemo.persistenceannotations.EnumeratedValueEntity */insert into enumerated_value_entity (priority,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.persistenceannotations.EnumeratedValueEntity */insert into enumerated_value_entity (priority,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [H]
|
||||
binding parameter (2:BIGINT) <- [1]
|
||||
/* insert for com.ankurm.hibernatedemo.persistenceannotations.EnumeratedValueEntity */insert into enumerated_value_entity (priority,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.persistenceannotations.EnumeratedValueEntity */insert into enumerated_value_entity (priority,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [H]
|
||||
binding parameter (2:BIGINT) <- [2]
|
||||
/* insert for com.ankurm.hibernatedemo.persistenceannotations.EnumeratedValueEntity */insert into enumerated_value_entity (priority,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.persistenceannotations.EnumeratedValueEntity */insert into enumerated_value_entity (priority,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [L]
|
||||
binding parameter (2:BIGINT) <- [3]
|
||||
/* select new com.ankurm.hibernatedemo.persistenceannotations.PriorityCountView(e.priority, count(e)) from EnumeratedValueEntity e group by e.priority order by e.priority */ select eve1_0.priority,count(eve1_0.id) from enumerated_value_entity eve1_0 group by eve1_0.priority order by eve1_0.priority
|
||||
Hibernate: /* select new com.ankurm.hibernatedemo.persistenceannotations.PriorityCountView(e.priority, count(e)) from EnumeratedValueEntity e group by e.priority order by e.priority */ select eve1_0.priority,count(eve1_0.id) from enumerated_value_entity eve1_0 group by eve1_0.priority order by eve1_0.priority
|
||||
RESULT[jpa32-record-constructor-expression]: [PriorityCountView[priority=HIGH, total=2], PriorityCountView[priority=LOW, total=1]]
|
||||
/* insert for com.ankurm.hibernatedemo.persistenceannotations.EnumeratedValueEntity */insert into enumerated_value_entity (priority,id) values (?,?)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.persistenceannotations.EnumeratedValueEntity */insert into enumerated_value_entity (priority,id) values (?,?)
|
||||
binding parameter (1:VARCHAR) <- [H]
|
||||
binding parameter (2:BIGINT) <- [4]
|
||||
/* dynamic native SQL query */ select priority from enumerated_value_entity where id = 4
|
||||
Hibernate: /* dynamic native SQL query */ select priority from enumerated_value_entity where id = 4
|
||||
select eve1_0.id,eve1_0.priority from enumerated_value_entity eve1_0 where eve1_0.id=?
|
||||
Hibernate: select eve1_0.id,eve1_0.priority from enumerated_value_entity eve1_0 where eve1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [4]
|
||||
RESULT[jpa32-enumeratedvalue]: raw DB value for HIGH = 'H' (neither ordinal '2' nor name 'HIGH' -- the @EnumeratedValue-annotated code 'H')
|
||||
/* select e from EnumeratedValueEntity e where e.id = :id */ select eve1_0.id,eve1_0.priority from enumerated_value_entity eve1_0 where eve1_0.id=?
|
||||
Hibernate: /* select e from EnumeratedValueEntity e where e.id = :id */ select eve1_0.id,eve1_0.priority from enumerated_value_entity eve1_0 where eve1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [-999]
|
||||
RESULT[jpa32-getsingleresultornull]: query matching zero rows via getSingleResultOrNull() = null (getSingleResult() would have thrown NoResultException here)
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
wrong parameter name 'employee_id' (procedure expects 'emp_id') threw: NOTHING -- bound positionally regardless of the name: tax_amount output = 7500.00
|
||||
swapped IN/OUT positional registration on GET_TAX threw: org.hibernate.exception.GenericJDBCException: Unable to register CallableStatement OUT parameter [Invalid argument in JDBC call: Not OUT or INOUT mode for parameter: 1] [n/a]
|
||||
emp_id (really IN) registered as ParameterMode.OUT threw: org.hibernate.exception.GenericJDBCException: Unable to register CallableStatement OUT parameter [Invalid argument in JDBC call: Not OUT or INOUT mode for parameter: 1] [n/a]
|
||||
getResultList() on a no-result-set procedure threw: java.lang.IllegalStateException: Current CallableStatement was not a ResultSet, but getResultList was called
|
||||
getOutputParameterValue() WITHOUT calling execute() first threw: NOTHING -- getOutputParameterValue() triggered execution implicitly (value=7500.00)
|
||||
COUNT_EMPLOYEES before persisting a new row = 2
|
||||
COUNT_EMPLOYEES after persist() but WITHOUT an explicit flush() = 2
|
||||
COUNT_EMPLOYEES after an explicit flush() = 3
|
||||
ProcedureCall with addSynchronizedEntityClass(ProcEmployee.class), unflushed Dave NOT counted: COUNT_EMPLOYEES = 2 (still just Alice+Bob -- addSynchronizedEntityClass had NO auto-flush effect here)
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
@NamedStoredProcedureQuery ProcEmployee.getTax(emp_id=1) execute()=false tax_amount=7500.00
|
||||
EntityManager.createStoredProcedureQuery("GET_TAX") for emp 2, tax_amount=9000.00
|
||||
Session.createStoredProcedureQuery("GET_TAX") for emp 1, tax_amount=7500.00
|
||||
INOUT parameter 'sal' after ADJUST_SALARY(1000.00, 10.00) = 1100.00
|
||||
ProcEmployee.listAll execute() returned false (HSQLDB misreports this as false)
|
||||
getResultList() on the (mis-reported) result-set procedure threw: java.lang.IllegalStateException: Current CallableStatement was not a ResultSet, but getResultList was called
|
||||
DTO-mapped getResultList() threw: java.lang.IllegalStateException: Current CallableStatement was not a ResultSet, but getResultList was called
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
=== Raw JDBC probe (no Hibernate), HSQLDB 2.7.3, DYNAMIC RESULT SETS procedure ===
|
||||
--- CallableStatement.execute() then getUpdateCount()/getResultSet() ---
|
||||
execute() returned=false
|
||||
getUpdateCount=0
|
||||
getResultSet() = org.hsqldb.jdbc.JDBCResultSet@5649fd9b
|
||||
row: 1 Alice 50000.00
|
||||
row: 2 Bob 60000.00
|
||||
getMoreResults=false
|
||||
|
||||
--- Statement.execute("CALL ...") vs CallableStatement.executeQuery() ---
|
||||
--- via plain Statement.execute(CALL ...) ---
|
||||
Statement.execute returned=false
|
||||
getResultSet=null
|
||||
--- via CallableStatement.executeQuery() ---
|
||||
executeQuery ok, rs=org.hsqldb.jdbc.JDBCResultSet@5649fd9b
|
||||
row via executeQuery: 1
|
||||
row via executeQuery: 2
|
||||
--- metadata: getMetaData() on CallableStatement before execute ---
|
||||
getMetaData()=null
|
||||
|
||||
CONCLUSION: CallableStatement.execute() returns false (per JDBC spec this should mean
|
||||
'no ResultSet, check update count'), and getUpdateCount() also returns 0 (not -1).
|
||||
Yet CallableStatement.getResultSet() DOES return a live, iterable ResultSet with the
|
||||
cursor's rows, and CallableStatement.executeQuery() works correctly end-to-end.
|
||||
Statement.execute("CALL ...") is worse: execute()=false AND getResultSet()=null (the
|
||||
result set is only reachable through the CallableStatement form).
|
||||
Hibernate 7.4.5's ProcedureCallImpl (org.hibernate.procedure.internal.ProcedureCallImpl
|
||||
/ StandardCallableStatementSupport) drives the call via execute() and trusts its boolean
|
||||
to decide whether to attach a ResultSetOutput. Since HSQLDB's driver misreports that
|
||||
boolean, getResultList() on a DYNAMIC RESULT SETS procedure fails with:
|
||||
java.lang.IllegalStateException: Current CallableStatement was not a ResultSet, but getResultList was called
|
||||
This reproduces identically through @NamedStoredProcedureQuery(resultClasses=...) and
|
||||
through createStoredProcedureQuery(name, sqlResultSetMappingName) -- see
|
||||
StoredProcedureHappyPathTest#resultSetProcedure_mappedToEntity_hitsHsqldbDriverIncompatibility
|
||||
and #resultSetProcedure_mappedToDto_alsoHitsHsqldbDriverIncompatibility.
|
||||
|
||||
=== OUT parameter vs result-set consumption ORDER (raw JDBC, procedure with BOTH) ===
|
||||
Procedure: combo(IN emp_id, OUT tax_amount) READS SQL DATA DYNAMIC RESULT SETS 1, opens a cursor
|
||||
AND sets the OUT parameter.
|
||||
|
||||
Reading the OUT parameter BEFORE consuming the ResultSet:
|
||||
execute()=false
|
||||
OUT tax_amount = 7500.00 <- succeeds, no exception
|
||||
(then) getResultSet() still returns the cursor with its rows intact
|
||||
(then) OUT tax_amount read AGAIN = 7500.00 <- still succeeds
|
||||
|
||||
Reading the OUT parameter AFTER fully consuming the ResultSet:
|
||||
rows consumed first
|
||||
OUT tax_amount = 9000.00 <- also succeeds
|
||||
|
||||
CONCLUSION: unlike some JDBC drivers (historically SQL Server's, and some Oracle configurations)
|
||||
that require a stored procedure's result set(s) to be fully consumed before OUT parameters
|
||||
become readable, HSQLDB 2.7.3's driver imposes NO such ordering constraint. Reading the OUT
|
||||
value before, interleaved with, or after draining the cursor all work identically. The
|
||||
"ordering trap" described in stored-procedure folklore is real on SOME databases/drivers but
|
||||
is NOT reproducible on HSQLDB -- worth stating explicitly rather than assuming it's universal.
|
||||
Executable
+139
@@ -0,0 +1,139 @@
|
||||
=== jakarta.persistence-api 3.2.0: NamedStoredProcedureQuery ===
|
||||
Compiled from "NamedStoredProcedureQuery.java"
|
||||
public interface jakarta.persistence.NamedStoredProcedureQuery extends java.lang.annotation.Annotation {
|
||||
public abstract java.lang.String name();
|
||||
public abstract java.lang.String procedureName();
|
||||
public abstract jakarta.persistence.StoredProcedureParameter[] parameters();
|
||||
public abstract java.lang.Class[] resultClasses();
|
||||
public abstract java.lang.String[] resultSetMappings();
|
||||
public abstract jakarta.persistence.QueryHint[] hints();
|
||||
}
|
||||
|
||||
=== jakarta.persistence-api 3.2.0: StoredProcedureParameter ===
|
||||
Compiled from "StoredProcedureParameter.java"
|
||||
public interface jakarta.persistence.StoredProcedureParameter extends java.lang.annotation.Annotation {
|
||||
public abstract java.lang.String name();
|
||||
public abstract jakarta.persistence.ParameterMode mode();
|
||||
public abstract java.lang.Class<?> type();
|
||||
}
|
||||
|
||||
=== jakarta.persistence-api 3.2.0: StoredProcedureQuery ===
|
||||
Compiled from "StoredProcedureQuery.java"
|
||||
public interface jakarta.persistence.StoredProcedureQuery extends jakarta.persistence.Query {
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setHint(java.lang.String, java.lang.Object);
|
||||
public abstract <T> jakarta.persistence.StoredProcedureQuery setParameter(jakarta.persistence.Parameter<T>, T);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setParameter(jakarta.persistence.Parameter<java.util.Calendar>, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setParameter(jakarta.persistence.Parameter<java.util.Date>, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setParameter(java.lang.String, java.lang.Object);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setParameter(java.lang.String, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setParameter(java.lang.String, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setParameter(int, java.lang.Object);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setParameter(int, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setParameter(int, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setFlushMode(jakarta.persistence.FlushModeType);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setCacheRetrieveMode(jakarta.persistence.CacheRetrieveMode);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setCacheStoreMode(jakarta.persistence.CacheStoreMode);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery setTimeout(java.lang.Integer);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery registerStoredProcedureParameter(int, java.lang.Class<?>, jakarta.persistence.ParameterMode);
|
||||
public abstract jakarta.persistence.StoredProcedureQuery registerStoredProcedureParameter(java.lang.String, java.lang.Class<?>, jakarta.persistence.ParameterMode);
|
||||
public abstract java.lang.Object getOutputParameterValue(int);
|
||||
public abstract java.lang.Object getOutputParameterValue(java.lang.String);
|
||||
public abstract boolean execute();
|
||||
public abstract int executeUpdate();
|
||||
public abstract java.util.List getResultList();
|
||||
public abstract java.lang.Object getSingleResult();
|
||||
public abstract java.lang.Object getSingleResultOrNull();
|
||||
public abstract boolean hasMoreResults();
|
||||
public abstract int getUpdateCount();
|
||||
public default jakarta.persistence.Query setTimeout(java.lang.Integer);
|
||||
public default jakarta.persistence.Query setCacheStoreMode(jakarta.persistence.CacheStoreMode);
|
||||
public default jakarta.persistence.Query setCacheRetrieveMode(jakarta.persistence.CacheRetrieveMode);
|
||||
public default jakarta.persistence.Query setFlushMode(jakarta.persistence.FlushModeType);
|
||||
public default jakarta.persistence.Query setParameter(int, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(int, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(int, java.lang.Object);
|
||||
public default jakarta.persistence.Query setParameter(java.lang.String, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(java.lang.String, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(java.lang.String, java.lang.Object);
|
||||
public default jakarta.persistence.Query setParameter(jakarta.persistence.Parameter, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(jakarta.persistence.Parameter, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(jakarta.persistence.Parameter, java.lang.Object);
|
||||
public default jakarta.persistence.Query setHint(java.lang.String, java.lang.Object);
|
||||
}
|
||||
|
||||
=== hibernate-core 7.4.5.Final: org.hibernate.procedure.ProcedureCall (native, JPA-superset) ===
|
||||
Compiled from "ProcedureCall.java"
|
||||
public interface org.hibernate.procedure.ProcedureCall extends org.hibernate.query.CommonQueryContract,org.hibernate.query.SynchronizeableQuery,jakarta.persistence.StoredProcedureQuery,java.lang.AutoCloseable {
|
||||
public static final java.lang.String FUNCTION_RETURN_TYPE_HINT;
|
||||
public abstract java.lang.String getProcedureName();
|
||||
public abstract boolean isFunctionCall();
|
||||
public abstract org.hibernate.procedure.ProcedureCall markAsFunctionCall(int);
|
||||
public abstract org.hibernate.procedure.ProcedureCall markAsFunctionCall(java.lang.Class<?>);
|
||||
public abstract org.hibernate.procedure.ProcedureCall markAsFunctionCall(jakarta.persistence.metamodel.Type<?>);
|
||||
public abstract <T> org.hibernate.procedure.ProcedureParameter<T> registerParameter(int, java.lang.Class<T>, jakarta.persistence.ParameterMode);
|
||||
public abstract <T> org.hibernate.procedure.ProcedureParameter<T> registerParameter(int, jakarta.persistence.metamodel.Type<T>, jakarta.persistence.ParameterMode);
|
||||
public abstract org.hibernate.procedure.ProcedureCall registerStoredProcedureParameter(int, jakarta.persistence.metamodel.Type<?>, jakarta.persistence.ParameterMode);
|
||||
public abstract org.hibernate.procedure.ProcedureParameter<?> getParameterRegistration(int);
|
||||
public abstract <T> org.hibernate.procedure.ProcedureParameter<T> registerParameter(java.lang.String, java.lang.Class<T>, jakarta.persistence.ParameterMode) throws org.hibernate.procedure.NamedParametersNotSupportedException;
|
||||
public abstract <T> org.hibernate.procedure.ProcedureParameter<T> registerParameter(java.lang.String, jakarta.persistence.metamodel.Type<T>, jakarta.persistence.ParameterMode) throws org.hibernate.procedure.NamedParametersNotSupportedException;
|
||||
public abstract org.hibernate.procedure.ProcedureCall registerStoredProcedureParameter(java.lang.String, jakarta.persistence.metamodel.Type<?>, jakarta.persistence.ParameterMode);
|
||||
public abstract org.hibernate.procedure.ProcedureParameter<?> getParameterRegistration(java.lang.String);
|
||||
public abstract java.util.List<org.hibernate.procedure.ProcedureParameter<?>> getRegisteredParameters();
|
||||
public abstract org.hibernate.procedure.ProcedureOutputs getOutputs();
|
||||
public abstract org.hibernate.procedure.FunctionReturn<?> getFunctionReturn();
|
||||
public default void close();
|
||||
public abstract org.hibernate.procedure.ProcedureCall addSynchronizedQuerySpace(java.lang.String);
|
||||
public abstract org.hibernate.procedure.ProcedureCall addSynchronizedEntityName(java.lang.String) throws org.hibernate.MappingException;
|
||||
public abstract org.hibernate.procedure.ProcedureCall addSynchronizedEntityClass(java.lang.Class) throws org.hibernate.MappingException;
|
||||
public abstract org.hibernate.procedure.ProcedureCall setHint(java.lang.String, java.lang.Object);
|
||||
public abstract <T> org.hibernate.procedure.ProcedureCall setParameter(jakarta.persistence.Parameter<T>, T);
|
||||
public abstract org.hibernate.procedure.ProcedureCall setParameter(jakarta.persistence.Parameter<java.util.Calendar>, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public abstract org.hibernate.procedure.ProcedureCall setParameter(jakarta.persistence.Parameter<java.util.Date>, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public abstract org.hibernate.procedure.ProcedureCall setParameter(java.lang.String, java.lang.Object);
|
||||
public abstract org.hibernate.procedure.ProcedureCall setParameter(java.lang.String, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public abstract org.hibernate.procedure.ProcedureCall setParameter(java.lang.String, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public abstract org.hibernate.procedure.ProcedureCall setParameter(int, java.lang.Object);
|
||||
public abstract org.hibernate.procedure.ProcedureCall setParameter(int, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public abstract org.hibernate.procedure.ProcedureCall setParameter(int, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public abstract org.hibernate.procedure.ProcedureCall setFlushMode(jakarta.persistence.FlushModeType);
|
||||
public abstract org.hibernate.procedure.ProcedureCall registerStoredProcedureParameter(int, java.lang.Class<?>, jakarta.persistence.ParameterMode);
|
||||
public abstract org.hibernate.procedure.ProcedureCall registerStoredProcedureParameter(java.lang.String, java.lang.Class<?>, jakarta.persistence.ParameterMode);
|
||||
public default org.hibernate.query.CommonQueryContract setParameter(jakarta.persistence.Parameter, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default org.hibernate.query.CommonQueryContract setParameter(jakarta.persistence.Parameter, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default org.hibernate.query.CommonQueryContract setParameter(jakarta.persistence.Parameter, java.lang.Object);
|
||||
public default org.hibernate.query.CommonQueryContract setParameter(int, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default org.hibernate.query.CommonQueryContract setParameter(int, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default org.hibernate.query.CommonQueryContract setParameter(int, java.lang.Object);
|
||||
public default org.hibernate.query.CommonQueryContract setParameter(java.lang.String, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default org.hibernate.query.CommonQueryContract setParameter(java.lang.String, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default org.hibernate.query.CommonQueryContract setParameter(java.lang.String, java.lang.Object);
|
||||
public default org.hibernate.query.CommonQueryContract setHint(java.lang.String, java.lang.Object);
|
||||
public default org.hibernate.query.CommonQueryContract setFlushMode(jakarta.persistence.FlushModeType);
|
||||
public default org.hibernate.query.SynchronizeableQuery addSynchronizedEntityClass(java.lang.Class) throws org.hibernate.MappingException;
|
||||
public default org.hibernate.query.SynchronizeableQuery addSynchronizedEntityName(java.lang.String) throws org.hibernate.MappingException;
|
||||
public default org.hibernate.query.SynchronizeableQuery addSynchronizedQuerySpace(java.lang.String);
|
||||
public default jakarta.persistence.StoredProcedureQuery registerStoredProcedureParameter(java.lang.String, java.lang.Class, jakarta.persistence.ParameterMode);
|
||||
public default jakarta.persistence.StoredProcedureQuery registerStoredProcedureParameter(int, java.lang.Class, jakarta.persistence.ParameterMode);
|
||||
public default jakarta.persistence.StoredProcedureQuery setFlushMode(jakarta.persistence.FlushModeType);
|
||||
public default jakarta.persistence.StoredProcedureQuery setParameter(int, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.StoredProcedureQuery setParameter(int, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.StoredProcedureQuery setParameter(int, java.lang.Object);
|
||||
public default jakarta.persistence.StoredProcedureQuery setParameter(java.lang.String, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.StoredProcedureQuery setParameter(java.lang.String, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.StoredProcedureQuery setParameter(java.lang.String, java.lang.Object);
|
||||
public default jakarta.persistence.StoredProcedureQuery setParameter(jakarta.persistence.Parameter, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.StoredProcedureQuery setParameter(jakarta.persistence.Parameter, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.StoredProcedureQuery setParameter(jakarta.persistence.Parameter, java.lang.Object);
|
||||
public default jakarta.persistence.StoredProcedureQuery setHint(java.lang.String, java.lang.Object);
|
||||
public default jakarta.persistence.Query setFlushMode(jakarta.persistence.FlushModeType);
|
||||
public default jakarta.persistence.Query setParameter(int, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(int, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(int, java.lang.Object);
|
||||
public default jakarta.persistence.Query setParameter(java.lang.String, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(java.lang.String, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(java.lang.String, java.lang.Object);
|
||||
public default jakarta.persistence.Query setParameter(jakarta.persistence.Parameter, java.util.Date, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(jakarta.persistence.Parameter, java.util.Calendar, jakarta.persistence.TemporalType);
|
||||
public default jakarta.persistence.Query setParameter(jakarta.persistence.Parameter, java.lang.Object);
|
||||
public default jakarta.persistence.Query setHint(java.lang.String, java.lang.Object);
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
# EntityGraphFetchTest -- filtered run output. JUnit does not run @Test methods in
|
||||
# declaration order, so match SQL shape to test by the FK columns selected, not by position:
|
||||
#
|
||||
# left join proxy_review only (no proxy_publisher columns) -> fetchgraph:
|
||||
# named attribute (reviews) joined; publisher forced to LAZY despite its EAGER mapping.
|
||||
# Confirmed by the very next line: "book.getPublisher() runtime class = ...HibernateProxy".
|
||||
# left join proxy_publisher only (no proxy_review columns) -> no graph at all:
|
||||
# plain find() honours the mapping as declared: publisher EAGER (joined), reviews LAZY (not joined).
|
||||
# left join proxy_publisher AND left join proxy_review -> loadgraph:
|
||||
# named attribute (reviews) joined AND the mapped-EAGER publisher stays joined too --
|
||||
# loadgraph only ADDS to the mapping's defaults, it never takes anything away.
|
||||
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [Graph Press]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
binding parameter (2:VARCHAR) <- [Graph Book]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
binding parameter (2:VARCHAR) <- [Nice graph]
|
||||
select pb1_0.id,pb1_0.publisher_id,pb1_0.title,r1_0.book_id,r1_0.id,r1_0.comment from proxy_book pb1_0 left join proxy_review r1_0 on pb1_0.id=r1_0.book_id where pb1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
fetchgraph: book.getPublisher() runtime class = com.ankurm.hibernatedemo.proxy.ProxyPublisher$HibernateProxy
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [Graph Press]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
binding parameter (2:VARCHAR) <- [Graph Book]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
binding parameter (2:VARCHAR) <- [Nice graph]
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [Graph Press]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
binding parameter (2:VARCHAR) <- [Graph Book]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
binding parameter (2:VARCHAR) <- [Nice graph]
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title,r1_0.book_id,r1_0.id,r1_0.comment from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id left join proxy_review r1_0 on pb1_0.id=r1_0.book_id where pb1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
|
||||
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0 -- EntityGraphFetchTest
|
||||
Executable
+125
@@ -0,0 +1,125 @@
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/tmp/tools/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
22:53:28.029 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.ankurm.hibernatedemo.proxy.EntityGraphFetchTest]: EntityGraphFetchTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
22:53:28.169 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.ankurm.hibernatedemo.HibernateDemoApplication for test class com.ankurm.hibernatedemo.proxy.EntityGraphFetchTest
|
||||
22:53:28.247 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.ankurm.hibernatedemo.proxy.EntityGraphFetchTest]: EntityGraphFetchTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
22:53:28.249 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.ankurm.hibernatedemo.HibernateDemoApplication for test class com.ankurm.hibernatedemo.proxy.EntityGraphFetchTest
|
||||
create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
Hibernate: create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
Hibernate: create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
create table proxy_book (id bigint generated by default as identity, title varchar(255), publisher_id bigint, primary key (id))
|
||||
Hibernate: create table proxy_book (id bigint generated by default as identity, title varchar(255), publisher_id bigint, primary key (id))
|
||||
create table proxy_publisher (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table proxy_publisher (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
create table proxy_review (id bigint generated by default as identity, comment varchar(255), book_id bigint, primary key (id))
|
||||
Hibernate: create table proxy_review (id bigint generated by default as identity, comment varchar(255), book_id bigint, primary key (id))
|
||||
create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
create sequence book_seq start with 1 increment by 50
|
||||
Hibernate: create sequence book_seq start with 1 increment by 50
|
||||
create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
Hibernate: create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
Hibernate: create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
create sequence widget_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_seq start with 1 increment by 25
|
||||
alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
Hibernate: alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
alter table if exists proxy_book add constraint FKdwgf9ornbhstryty5erv6yks3 foreign key (publisher_id) references proxy_publisher
|
||||
Hibernate: alter table if exists proxy_book add constraint FKdwgf9ornbhstryty5erv6yks3 foreign key (publisher_id) references proxy_publisher
|
||||
alter table if exists proxy_review add constraint FKt4m0nd9t6swvakhmcnm0xclio foreign key (book_id) references proxy_book
|
||||
Hibernate: alter table if exists proxy_review add constraint FKt4m0nd9t6swvakhmcnm0xclio foreign key (book_id) references proxy_book
|
||||
Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build as described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html#0.3
|
||||
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
|
||||
WARNING: A Java agent has been loaded dynamically (/sessions/intelligent-loving-cori/.m2/repository/net/bytebuddy/byte-buddy-agent/1.18.11/byte-buddy-agent-1.18.11.jar)
|
||||
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
|
||||
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
|
||||
WARNING: Dynamic loading of agents will be disallowed by default in a future release
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [Graph Press]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
binding parameter (2:VARCHAR) <- [Graph Book]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
binding parameter (2:VARCHAR) <- [Nice graph]
|
||||
select pb1_0.id,pb1_0.publisher_id,pb1_0.title,r1_0.book_id,r1_0.id,r1_0.comment from proxy_book pb1_0 left join proxy_review r1_0 on pb1_0.id=r1_0.book_id where pb1_0.id=?
|
||||
Hibernate: select pb1_0.id,pb1_0.publisher_id,pb1_0.title,r1_0.book_id,r1_0.id,r1_0.comment from proxy_book pb1_0 left join proxy_review r1_0 on pb1_0.id=r1_0.book_id where pb1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
fetchgraph: book.getPublisher() runtime class = com.ankurm.hibernatedemo.proxy.ProxyPublisher$HibernateProxy
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [Graph Press]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
binding parameter (2:VARCHAR) <- [Graph Book]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
binding parameter (2:VARCHAR) <- [Nice graph]
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
Hibernate: select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [Graph Press]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
binding parameter (2:VARCHAR) <- [Graph Book]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
binding parameter (2:VARCHAR) <- [Nice graph]
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title,r1_0.book_id,r1_0.id,r1_0.comment from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id left join proxy_review r1_0 on pb1_0.id=r1_0.book_id where pb1_0.id=?
|
||||
Hibernate: select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title,r1_0.book_id,r1_0.id,r1_0.comment from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id left join proxy_review r1_0 on pb1_0.id=r1_0.book_id where pb1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
Executable
+156
@@ -0,0 +1,156 @@
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/tmp/tools/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
22:53:20.581 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.ankurm.hibernatedemo.proxy.ProxyIdentityTest]: ProxyIdentityTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
22:53:20.749 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.ankurm.hibernatedemo.HibernateDemoApplication for test class com.ankurm.hibernatedemo.proxy.ProxyIdentityTest
|
||||
22:53:20.823 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.ankurm.hibernatedemo.proxy.ProxyIdentityTest]: ProxyIdentityTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
22:53:20.825 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.ankurm.hibernatedemo.HibernateDemoApplication for test class com.ankurm.hibernatedemo.proxy.ProxyIdentityTest
|
||||
create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
Hibernate: create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
Hibernate: create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
create table proxy_book (id bigint generated by default as identity, title varchar(255), publisher_id bigint, primary key (id))
|
||||
Hibernate: create table proxy_book (id bigint generated by default as identity, title varchar(255), publisher_id bigint, primary key (id))
|
||||
create table proxy_publisher (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table proxy_publisher (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
create table proxy_review (id bigint generated by default as identity, comment varchar(255), book_id bigint, primary key (id))
|
||||
Hibernate: create table proxy_review (id bigint generated by default as identity, comment varchar(255), book_id bigint, primary key (id))
|
||||
create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
create sequence book_seq start with 1 increment by 50
|
||||
Hibernate: create sequence book_seq start with 1 increment by 50
|
||||
create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
Hibernate: create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
Hibernate: create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
create sequence widget_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_seq start with 1 increment by 25
|
||||
alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
Hibernate: alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
alter table if exists proxy_book add constraint FKdwgf9ornbhstryty5erv6yks3 foreign key (publisher_id) references proxy_publisher
|
||||
Hibernate: alter table if exists proxy_book add constraint FKdwgf9ornbhstryty5erv6yks3 foreign key (publisher_id) references proxy_publisher
|
||||
alter table if exists proxy_review add constraint FKt4m0nd9t6swvakhmcnm0xclio foreign key (book_id) references proxy_book
|
||||
Hibernate: alter table if exists proxy_review add constraint FKt4m0nd9t6swvakhmcnm0xclio foreign key (book_id) references proxy_book
|
||||
Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build as described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html#0.3
|
||||
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
|
||||
WARNING: A Java agent has been loaded dynamically (/sessions/intelligent-loving-cori/.m2/repository/net/bytebuddy/byte-buddy-agent/1.18.11/byte-buddy-agent-1.18.11.jar)
|
||||
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
|
||||
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
|
||||
WARNING: Dynamic loading of agents will be disallowed by default in a future release
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [Identity Press]
|
||||
getReference() runtime class: com.ankurm.hibernatedemo.proxy.ProxyPublisher$HibernateProxy
|
||||
select pp1_0.id,pp1_0.name from proxy_publisher pp1_0 where pp1_0.id=?
|
||||
Hibernate: select pp1_0.id,pp1_0.name from proxy_publisher pp1_0 where pp1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [Naive Equals Press]
|
||||
select pp1_0.id,pp1_0.name from proxy_publisher pp1_0 where pp1_0.id=?
|
||||
Hibernate: select pp1_0.id,pp1_0.name from proxy_publisher pp1_0 where pp1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [O'Reilly]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
binding parameter (2:VARCHAR) <- [Effective Hibernate]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
binding parameter (2:VARCHAR) <- [Great book]
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
Hibernate: select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
verbatim exception class: org.hibernate.LazyInitializationException
|
||||
verbatim exception message: Cannot lazily initialize collection of role 'com.ankurm.hibernatedemo.proxy.ProxyBook.reviews' with key '1' (no session)
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [O'Reilly]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [4]
|
||||
binding parameter (2:VARCHAR) <- [Initialize Me]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
binding parameter (2:VARCHAR) <- [Great book]
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
Hibernate: select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
select r1_0.book_id,r1_0.id,r1_0.comment from proxy_review r1_0 where r1_0.book_id=?
|
||||
Hibernate: select r1_0.book_id,r1_0.id,r1_0.comment from proxy_review r1_0 where r1_0.book_id=?
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [O'Reilly]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [5]
|
||||
binding parameter (2:VARCHAR) <- [To-One Proxy Message]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [3]
|
||||
binding parameter (2:VARCHAR) <- [Great book]
|
||||
to-one proxy verbatim message: Could not initialize proxy [com.ankurm.hibernatedemo.proxy.ProxyBook#3] - no session
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [O'Reilly]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [6]
|
||||
binding parameter (2:VARCHAR) <- [Unproxy Me]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [4]
|
||||
binding parameter (2:VARCHAR) <- [Great book]
|
||||
getReference() proxy class: com.ankurm.hibernatedemo.proxy.ProxyBook$HibernateProxy
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
Hibernate: select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [4]
|
||||
Hibernate.unproxy(proxy) class: com.ankurm.hibernatedemo.proxy.ProxyBook
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
# LazyInitializationTest + ProxyIdentityTest -- filtered run output (DEMO log lines only)
|
||||
# Full raw run: proxy-lazy-and-identity-run.txt
|
||||
|
||||
getReference() runtime class: com.ankurm.hibernatedemo.proxy.ProxyPublisher$HibernateProxy
|
||||
select pp1_0.id,pp1_0.name from proxy_publisher pp1_0 where pp1_0.id=?
|
||||
Hibernate: select pp1_0.id,pp1_0.name from proxy_publisher pp1_0 where pp1_0.id=?
|
||||
select pp1_0.id,pp1_0.name from proxy_publisher pp1_0 where pp1_0.id=?
|
||||
Hibernate: select pp1_0.id,pp1_0.name from proxy_publisher pp1_0 where pp1_0.id=?
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
Hibernate: select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
verbatim exception class: org.hibernate.LazyInitializationException
|
||||
verbatim exception message: Cannot lazily initialize collection of role 'com.ankurm.hibernatedemo.proxy.ProxyBook.reviews' with key '1' (no session)
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
Hibernate: select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
to-one proxy verbatim message: Could not initialize proxy [com.ankurm.hibernatedemo.proxy.ProxyBook#3] - no session
|
||||
getReference() proxy class: com.ankurm.hibernatedemo.proxy.ProxyBook$HibernateProxy
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
Hibernate: select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
Hibernate.unproxy(proxy) class: com.ankurm.hibernatedemo.proxy.ProxyBook
|
||||
|
||||
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0 -- LazyInitializationTest
|
||||
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 -- ProxyIdentityTest
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
# OpenInViewAndLazyLoadNoTransTest + OsivDefaultWarningTest + OsivDisabledExceptionTest
|
||||
# filtered run output
|
||||
|
||||
enable_lazy_load_no_trans=true: proxy.getTitle() after close returned 'No-Trans Book' with no exception
|
||||
spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
|
||||
checked at context-startup time: the OSIV warning line is present in the captured log
|
||||
default OSIV (true): GET /osiv/books/1 -> status 200, body {"title":"OSIV Default Book","publisher":{"name":"OSIV Default Press","id":1},"id":1,"reviews":[{"comment":"Rendered fine","id":1}]}
|
||||
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Cannot lazily initialize collection of role 'com.ankurm.hibernatedemo.proxy.ProxyBook.reviews' with key '2' (no session)]
|
||||
open-in-view=false: GET /osiv/books/2 -> status 500, body {"timestamp":"2026-09-05T17:23:41.574Z","status":500,"error":"Internal Server Error","path":"/osiv/books/2"}
|
||||
|
||||
Tests run: 1 -- OpenInViewAndLazyLoadNoTransTest (enable_lazy_load_no_trans=true)
|
||||
Tests run: 1 -- OsivDefaultWarningTest (open-in-view left unset -> Boot default true)
|
||||
Tests run: 1 -- OsivDisabledExceptionTest (open-in-view=false)
|
||||
Executable
+179
@@ -0,0 +1,179 @@
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/tmp/tools/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
22:53:35.358 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.ankurm.hibernatedemo.proxy.OpenInViewAndLazyLoadNoTransTest]: OpenInViewAndLazyLoadNoTransTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
22:53:35.483 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.ankurm.hibernatedemo.HibernateDemoApplication for test class com.ankurm.hibernatedemo.proxy.OpenInViewAndLazyLoadNoTransTest
|
||||
22:53:35.551 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.ankurm.hibernatedemo.proxy.OpenInViewAndLazyLoadNoTransTest]: OpenInViewAndLazyLoadNoTransTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
22:53:35.553 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.ankurm.hibernatedemo.HibernateDemoApplication for test class com.ankurm.hibernatedemo.proxy.OpenInViewAndLazyLoadNoTransTest
|
||||
create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
Hibernate: create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
Hibernate: create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
create table proxy_book (id bigint generated by default as identity, title varchar(255), publisher_id bigint, primary key (id))
|
||||
Hibernate: create table proxy_book (id bigint generated by default as identity, title varchar(255), publisher_id bigint, primary key (id))
|
||||
create table proxy_publisher (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table proxy_publisher (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
create table proxy_review (id bigint generated by default as identity, comment varchar(255), book_id bigint, primary key (id))
|
||||
Hibernate: create table proxy_review (id bigint generated by default as identity, comment varchar(255), book_id bigint, primary key (id))
|
||||
create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
create sequence book_seq start with 1 increment by 50
|
||||
Hibernate: create sequence book_seq start with 1 increment by 50
|
||||
create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
Hibernate: create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
Hibernate: create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
create sequence widget_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_seq start with 1 increment by 25
|
||||
alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
Hibernate: alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
alter table if exists proxy_book add constraint FKdwgf9ornbhstryty5erv6yks3 foreign key (publisher_id) references proxy_publisher
|
||||
Hibernate: alter table if exists proxy_book add constraint FKdwgf9ornbhstryty5erv6yks3 foreign key (publisher_id) references proxy_publisher
|
||||
alter table if exists proxy_review add constraint FKt4m0nd9t6swvakhmcnm0xclio foreign key (book_id) references proxy_book
|
||||
Hibernate: alter table if exists proxy_review add constraint FKt4m0nd9t6swvakhmcnm0xclio foreign key (book_id) references proxy_book
|
||||
Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build as described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html#0.3
|
||||
WARNING: A Java agent has been loaded dynamically (/sessions/intelligent-loving-cori/.m2/repository/net/bytebuddy/byte-buddy-agent/1.18.11/byte-buddy-agent-1.18.11.jar)
|
||||
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
|
||||
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
|
||||
WARNING: Dynamic loading of agents will be disallowed by default in a future release
|
||||
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [No-Trans Press]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
binding parameter (2:VARCHAR) <- [No-Trans Book]
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
Hibernate: select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [1]
|
||||
enable_lazy_load_no_trans=true: proxy.getTitle() after close returned 'No-Trans Book' with no exception
|
||||
|
||||
. ____ _ __ _ _
|
||||
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
|
||||
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
|
||||
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||
' |____| .__|_| |_|_| |_\__, | / / / /
|
||||
=========|_|==============|___/=/_/_/_/
|
||||
|
||||
:: Spring Boot :: (v4.1.1)
|
||||
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create table book (id bigint not null, author varchar(255), status varchar(255), title varchar(255), version bigint not null, primary key (id))
|
||||
Hibernate: create table note (id bigint generated by default as identity, text varchar(255), book_id bigint, primary key (id))
|
||||
Hibernate: create table proxy_book (id bigint generated by default as identity, title varchar(255), publisher_id bigint, primary key (id))
|
||||
Hibernate: create table proxy_publisher (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table proxy_review (id bigint generated by default as identity, comment varchar(255), book_id bigint, primary key (id))
|
||||
Hibernate: create table widget_alloc1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_alloc50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep1 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep10 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep25 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_batch_sweep50 (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_identity (id bigint generated by default as identity, name varchar(255), primary key (id))
|
||||
Hibernate: create table widget_sequence (id bigint not null, name varchar(255), primary key (id))
|
||||
Hibernate: create sequence book_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_alloc10_seq start with 1 increment by 10
|
||||
Hibernate: create sequence widget_alloc1_seq start with 1 increment by 1
|
||||
Hibernate: create sequence widget_alloc25_seq start with 1 increment by 25
|
||||
Hibernate: create sequence widget_alloc50_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_batch_sweep1_seq start with 1 increment by 50
|
||||
Hibernate: create sequence widget_seq start with 1 increment by 25
|
||||
Hibernate: alter table if exists note add constraint FKrussm9y4vwyp0x6gl8n288ovv foreign key (book_id) references book
|
||||
Hibernate: alter table if exists proxy_book add constraint FKdwgf9ornbhstryty5erv6yks3 foreign key (publisher_id) references proxy_publisher
|
||||
Hibernate: alter table if exists proxy_review add constraint FKt4m0nd9t6swvakhmcnm0xclio foreign key (book_id) references proxy_book
|
||||
spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
|
||||
checked at context-startup time: the OSIV warning line is present in the captured log
|
||||
Hibernate: insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
Hibernate: select r1_0.book_id,r1_0.id,r1_0.comment from proxy_review r1_0 where r1_0.book_id=?
|
||||
default OSIV (true): GET /osiv/books/1 -> status 200, body {"title":"OSIV Default Book","publisher":{"name":"OSIV Default Press","id":1},"id":1,"reviews":[{"comment":"Rendered fine","id":1}]}
|
||||
create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep1(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_book(rn_ integer not null, id bigint, version bigint, author varchar(255), status varchar(255), title varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc25(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_sequence(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_alloc10(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
Hibernate: create global temporary table HTE_widget_batch_sweep50(rn_ integer not null, id bigint, name varchar(255), primary key (rn_)) transactional
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyPublisher */insert into proxy_publisher (name,id) values (?,default)
|
||||
binding parameter (1:VARCHAR) <- [OSIV Disabled Press]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyBook */insert into proxy_book (publisher_id,title,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
binding parameter (2:VARCHAR) <- [OSIV Disabled Book]
|
||||
/* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
Hibernate: /* insert for com.ankurm.hibernatedemo.proxy.ProxyReview */insert into proxy_review (book_id,comment,id) values (?,?,default)
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
binding parameter (2:VARCHAR) <- [Never rendered]
|
||||
select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
Hibernate: select pb1_0.id,p1_0.id,p1_0.name,pb1_0.title from proxy_book pb1_0 left join proxy_publisher p1_0 on p1_0.id=pb1_0.publisher_id where pb1_0.id=?
|
||||
binding parameter (1:BIGINT) <- [2]
|
||||
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Cannot lazily initialize collection of role 'com.ankurm.hibernatedemo.proxy.ProxyBook.reviews' with key '2' (no session)]
|
||||
open-in-view=false: GET /osiv/books/2 -> status 500, body {"timestamp":"2026-09-05T17:23:41.574Z","status":500,"error":"Internal Server Error","path":"/osiv/books/2"}
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
# javap org.hibernate.Hibernate (hibernate-core-7.4.5.Final.jar)
|
||||
Compiled from "Hibernate.java"
|
||||
public final class org.hibernate.Hibernate {
|
||||
public static void initialize(java.lang.Object) throws org.hibernate.HibernateException;
|
||||
public static boolean isInitialized(java.lang.Object);
|
||||
public static int size(java.util.Collection<?>);
|
||||
public static boolean isEmpty(java.util.Collection<?>);
|
||||
public static <T> boolean contains(java.util.Collection<? super T>, T);
|
||||
public static <K, V> V get(java.util.Map<? super K, V>, K);
|
||||
public static <T> T get(java.util.List<T>, int);
|
||||
public static <T> java.lang.Class<? extends T> getClass(T);
|
||||
public static <T> java.lang.Class<? extends T> getClassLazy(T);
|
||||
public static boolean isInstance(java.lang.Object, java.lang.Class<?>);
|
||||
public static <E> boolean isPropertyInitialized(E, jakarta.persistence.metamodel.Attribute<? super E, ?>);
|
||||
public static boolean isPropertyInitialized(java.lang.Object, java.lang.String);
|
||||
public static <E> void initializeProperty(E, jakarta.persistence.metamodel.Attribute<? super E, ?>);
|
||||
public static void initializeProperty(java.lang.Object, java.lang.String);
|
||||
public static java.lang.Object unproxy(java.lang.Object);
|
||||
public static <T> T unproxy(T, java.lang.Class<T>);
|
||||
public static <E> E createDetachedProxy(org.hibernate.SessionFactory, java.lang.Class<E>, java.lang.Object);
|
||||
public static <U> org.hibernate.Hibernate$CollectionInterface<java.util.Collection<U>> bag();
|
||||
public static <U> org.hibernate.Hibernate$CollectionInterface<java.util.Set<U>> set();
|
||||
public static <U> org.hibernate.Hibernate$CollectionInterface<java.util.List<U>> list();
|
||||
public static <U, V> org.hibernate.Hibernate$CollectionInterface<java.util.Map<U, V>> map();
|
||||
public static <U> org.hibernate.Hibernate$CollectionInterface<java.util.SortedSet<U>> sortedSet();
|
||||
public static <U, V> org.hibernate.Hibernate$CollectionInterface<java.util.Map<U, V>> sortedMap();
|
||||
public static <C> org.hibernate.Hibernate$CollectionInterface<C> collection(java.lang.Class<C>);
|
||||
public static org.hibernate.LobHelper getLobHelper();
|
||||
static {};
|
||||
}
|
||||
|
||||
# javap org.hibernate.cfg.TransactionSettings -- confirms hibernate.enable_lazy_load_no_trans still exists, annotated @Unsafe
|
||||
Compiled from "TransactionSettings.java"
|
||||
public interface org.hibernate.cfg.TransactionSettings {
|
||||
public static final java.lang.String TRANSACTION_COORDINATOR_STRATEGY;
|
||||
public static final java.lang.String JTA_PLATFORM;
|
||||
public static final java.lang.String JTA_PLATFORM_RESOLVER;
|
||||
public static final java.lang.String PREFER_USER_TRANSACTION;
|
||||
public static final java.lang.String JTA_CACHE_TM;
|
||||
public static final java.lang.String JTA_CACHE_UT;
|
||||
public static final java.lang.String JTA_TRACK_BY_THREAD;
|
||||
public static final java.lang.String ALLOW_JTA_TRANSACTION_ACCESS;
|
||||
public static final java.lang.String AUTO_CLOSE_SESSION;
|
||||
public static final java.lang.String FLUSH_BEFORE_COMPLETION;
|
||||
public static final java.lang.String ENABLE_LAZY_LOAD_NO_TRANS;
|
||||
public static final java.lang.String ALLOW_UPDATE_OUTSIDE_TRANSACTION;
|
||||
}
|
||||
|
||||
# javap org.hibernate.cfg.Unsafe -- marker annotation, no members
|
||||
Compiled from "Unsafe.java"
|
||||
public interface org.hibernate.cfg.Unsafe extends java.lang.annotation.Annotation {
|
||||
}
|
||||
|
||||
# javap org.hibernate.cfg.BytecodeSettings
|
||||
Compiled from "BytecodeSettings.java"
|
||||
public interface org.hibernate.cfg.BytecodeSettings {
|
||||
public static final java.lang.String BYTECODE_PROVIDER;
|
||||
public static final java.lang.String BYTECODE_PROVIDER_INSTANCE;
|
||||
public static final java.lang.String ENHANCER_ENABLE_ASSOCIATION_MANAGEMENT;
|
||||
public static final java.lang.String ENHANCER_ENABLE_DIRTY_TRACKING;
|
||||
public static final java.lang.String ENHANCER_ENABLE_LAZY_INITIALIZATION;
|
||||
}
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
# Same TestDbWidget mapping, actual create table/sequence DDL captured per database
|
||||
# (H2 plain, H2 MODE=PostgreSQL, H2 MODE=Oracle, HSQLDB, Derby)
|
||||
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
23:16:46.378 [main] INFO DEMO -- db=H2 -> resolved dialect = org.hibernate.dialect.H2Dialect
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
23:16:47.094 [main] INFO DEMO -- db=DERBY -> resolved dialect = org.hibernate.community.dialect.DerbyDialect
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
23:16:47.175 [main] INFO DEMO -- db=H2_POSTGRES_MODE -> resolved dialect = org.hibernate.dialect.H2Dialect
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
23:16:47.409 [main] INFO DEMO -- db=HSQLDB -> resolved dialect = org.hibernate.dialect.HSQLDialect
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
23:16:47.458 [main] INFO DEMO -- db=H2_ORACLE_MODE -> resolved dialect = org.hibernate.dialect.H2Dialect
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
# CrossDatabaseBehaviorTest -- filtered run output
|
||||
|
||||
23:20:04.009 [main] INFO DEMO -- unquoted 'value' column, db=H2 -> succeeded=false, detail=JdbcSQLSyntaxErrorException: Syntax error in SQL statement "create table reserved_word_test (id integer, [*]value integer)"; expected "identifier"; SQL statement:
|
||||
23:20:04.011 [main] INFO DEMO -- unquoted 'value' column, db=HSQLDB -> succeeded=true, detail=CREATE TABLE succeeded with an unquoted 'value' column
|
||||
23:20:04.011 [main] INFO DEMO -- unquoted 'value' column, db=DERBY -> succeeded=true, detail=CREATE TABLE succeeded with an unquoted 'value' column
|
||||
23:20:04.242 [main] INFO DEMO -- CHAR(10) holding 'AB', db=H2 -> getString() = [AB ], length=10
|
||||
23:20:04.242 [main] INFO DEMO -- CHAR(10) holding 'AB', db=HSQLDB -> getString() = [AB ], length=10
|
||||
23:20:04.242 [main] INFO DEMO -- CHAR(10) holding 'AB', db=DERBY -> getString() = [AB ], length=10
|
||||
|
||||
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/tmp/tools/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
23:20:04.009 [main] INFO DEMO -- unquoted 'value' column, db=H2 -> succeeded=false, detail=JdbcSQLSyntaxErrorException: Syntax error in SQL statement "create table reserved_word_test (id integer, [*]value integer)"; expected "identifier"; SQL statement:
|
||||
create table reserved_word_test (id integer, value integer) [42001-240]
|
||||
23:20:04.011 [main] INFO DEMO -- unquoted 'value' column, db=HSQLDB -> succeeded=true, detail=CREATE TABLE succeeded with an unquoted 'value' column
|
||||
23:20:04.011 [main] INFO DEMO -- unquoted 'value' column, db=DERBY -> succeeded=true, detail=CREATE TABLE succeeded with an unquoted 'value' column
|
||||
23:20:04.242 [main] INFO DEMO -- CHAR(10) holding 'AB', db=H2 -> getString() = [AB ], length=10
|
||||
23:20:04.242 [main] INFO DEMO -- CHAR(10) holding 'AB', db=HSQLDB -> getString() = [AB ], length=10
|
||||
23:20:04.242 [main] INFO DEMO -- CHAR(10) holding 'AB', db=DERBY -> getString() = [AB ], length=10
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# Two real failures hit while wiring up Derby 10.16.1.1 against Hibernate ORM 7.4.5.Final.
|
||||
# Both captured verbatim from actual test/debug runs in this sandbox.
|
||||
|
||||
## Failure 1: dialect auto-detection refuses to guess for Derby
|
||||
# (hibernate.dialect NOT set -- relying on JDBC metadata auto-detection, which works fine for
|
||||
# both H2 and HSQLDB in this same test suite)
|
||||
|
||||
org.hibernate.HibernateException: Unable to determine Dialect for Apache Derby 10.16 (please set 'hibernate.dialect' or register a Dialect resolver)
|
||||
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.determineDialect(DialectFactoryImpl.java:202)
|
||||
at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:86)
|
||||
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$1.execute(JdbcEnvironmentInitiator.java:398)
|
||||
|
||||
# Note: the JDBC connection itself succeeded (product name/version WAS read: "Apache Derby
|
||||
# 10.16") -- this is not a connectivity problem, it's Hibernate's dialect resolver chain simply
|
||||
# not recognizing that product/version pair anymore.
|
||||
|
||||
## Failure 2: the "obvious" fix (set hibernate.dialect explicitly to the old FQCN) also fails
|
||||
# hibernate.dialect=org.hibernate.dialect.DerbyDialect
|
||||
|
||||
Caused by: org.hibernate.boot.registry.classloading.spi.ClassLoadingException: Unable to load class [org.hibernate.dialect.DerbyDialect]
|
||||
Caused by: java.lang.ClassNotFoundException: Could not load requested class: org.hibernate.dialect.DerbyDialect
|
||||
|
||||
# org.hibernate.dialect.DerbyDialect does not exist anywhere in hibernate-core-7.4.5.Final.jar
|
||||
# (confirmed: unzip -l hibernate-core-7.4.5.Final.jar | grep -i derby -> zero matches).
|
||||
|
||||
## The actual fix
|
||||
|
||||
# Add org.hibernate.orm:hibernate-community-dialects:7.4.5.Final (a SEPARATE artifact,
|
||||
# NOT pulled in by hibernate-core, spring-boot-starter-data-jpa, or any Spring Boot starter)
|
||||
# and set:
|
||||
# hibernate.dialect=org.hibernate.community.dialect.DerbyDialect
|
||||
# Confirmed present: unzip -l hibernate-community-dialects-7.4.5.Final.jar | grep -i derby
|
||||
# -> org/hibernate/community/dialect/DerbyDialect.class (and DerbyLegacyDialect, for older
|
||||
# Derby versions, also in this module).
|
||||
Executable
+369
@@ -0,0 +1,369 @@
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/tmp/tools/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
23:16:44.846 [main] INFO org.hibernate.orm.core -- HHH000001: Hibernate ORM core version 7.4.5.Final
|
||||
23:16:45.153 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:16:45.346 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:h2:mem:testdb-plain;DB_CLOSE_DELAY=-1]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Default catalog/schema: TESTDB-PLAIN/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 100
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
Hibernate: create global temporary table HTE_TestDbWidget(active boolean, order integer, rn_ integer not null, sku varchar(5), id bigint, description clob, primary key (rn_)) transactional
|
||||
23:16:46.348 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
23:16:46.378 [main] INFO DEMO -- db=H2 -> resolved dialect = org.hibernate.dialect.H2Dialect
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
23:16:46.444 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:16:46.955 [main] WARN org.hibernate.orm.jdbc -- HHH100123: Low default JDBC fetch size: 1 (consider setting 'hibernate.jdbc.fetch_size')
|
||||
23:16:46.955 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:derby:memory:testdb-plain;create=true]
|
||||
Database driver: Apache Derby Embedded JDBC Driver
|
||||
Database dialect: DerbyDialect
|
||||
Database version: 10.16.1
|
||||
Default catalog/schema: undefined/APP
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 1
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
23:16:46.986 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table TestDbWidget
|
||||
23:16:47.041 [main] WARN org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl -- GenerationTarget encountered exception accepting command : Error executing DDL "drop table TestDbWidget" via JDBC ['DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.]
|
||||
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "drop table TestDbWidget" via JDBC ['DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.]
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:91)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlString(Helper.java:218)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlStrings(Helper.java:204)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropTables(SchemaDropperImpl.java:376)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropConstraintsTablesSequences(SchemaDropperImpl.java:248)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:210)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:182)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:152)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:227)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$1(SchemaManagementToolCoordinator.java:101)
|
||||
at java.base/java.util.HashMap.forEach(HashMap.java:1430)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:100)
|
||||
at org.hibernate.boot.internal.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:35)
|
||||
at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:33)
|
||||
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:327)
|
||||
at org.hibernate.internal.SessionFactoryRegistry.instantiateSessionFactory(SessionFactoryRegistry.java:64)
|
||||
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:458)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:200)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:72)
|
||||
at com.ankurm.hibernatedemo.testdb.TestDbSupport.buildSessionFactory(TestDbSupport.java:73)
|
||||
at com.ankurm.hibernatedemo.testdb.DialectAndDdlTest.resolvedDialect(DialectAndDdlTest.java:23)
|
||||
at com.ankurm.hibernatedemo.testdb.DialectAndDdlTest.derby_resolvesDerbyDialect_fromTheCommunityDialectsModule_notHibernateCore(DialectAndDdlTest.java:65)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:701)
|
||||
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:502)
|
||||
at org.junit.jupiter.engine.support.MethodReflectionUtils.invoke(MethodReflectionUtils.java:45)
|
||||
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:61)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:124)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:163)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:148)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:123)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:105)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:99)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:66)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:47)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:39)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:104)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:98)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invokeVoid(InterceptingExecutableInvoker.java:71)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$0(TestMethodTestDescriptor.java:219)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:215)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:157)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:70)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:176)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:36)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:52)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:58)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.executeEngine(EngineExecutionOrchestrator.java:246)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.failOrExecuteEngine(EngineExecutionOrchestrator.java:218)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:179)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:66)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:157)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:65)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:125)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$2(InterceptingLauncher.java:57)
|
||||
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:56)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:125)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithCancellationToken(LauncherAdapter.java:68)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:54)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
|
||||
Caused by: java.sql.SQLSyntaxErrorException: 'DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.
|
||||
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:103)
|
||||
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Util.java:230)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(TransactionResourceImpl.java:431)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(TransactionResourceImpl.java:360)
|
||||
at org.apache.derby.impl.jdbc.EmbedConnection.handleException(EmbedConnection.java:2400)
|
||||
at org.apache.derby.impl.jdbc.ConnectionChild.handleException(ConnectionChild.java:86)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:697)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:637)
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:86)
|
||||
... 103 common frames omitted
|
||||
Caused by: ERROR 42Y55: 'DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:299)
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:294)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.justGetDescriptor(DDLStatementNode.java:366)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.getTableDescriptor(DDLStatementNode.java:337)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.getTableDescriptor(DDLStatementNode.java:289)
|
||||
at org.apache.derby.impl.sql.compile.DropTableNode.bindStatement(DropTableNode.java:98)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepMinion(GenericStatement.java:401)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepare(GenericStatement.java:99)
|
||||
at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(GenericLanguageConnectionContext.java:1114)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:689)
|
||||
... 105 common frames omitted
|
||||
Hibernate: drop sequence TestDbWidget_SEQ restrict
|
||||
23:16:47.046 [main] WARN org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl -- GenerationTarget encountered exception accepting command : Error executing DDL "drop sequence TestDbWidget_SEQ restrict" via JDBC ['DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.]
|
||||
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "drop sequence TestDbWidget_SEQ restrict" via JDBC ['DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.]
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:91)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlString(Helper.java:218)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlStrings(Helper.java:204)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropSequences(SchemaDropperImpl.java:335)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropConstraintsTablesSequences(SchemaDropperImpl.java:261)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:210)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:182)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:152)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:227)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$1(SchemaManagementToolCoordinator.java:101)
|
||||
at java.base/java.util.HashMap.forEach(HashMap.java:1430)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:100)
|
||||
at org.hibernate.boot.internal.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:35)
|
||||
at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:33)
|
||||
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:327)
|
||||
at org.hibernate.internal.SessionFactoryRegistry.instantiateSessionFactory(SessionFactoryRegistry.java:64)
|
||||
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:458)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:200)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:72)
|
||||
at com.ankurm.hibernatedemo.testdb.TestDbSupport.buildSessionFactory(TestDbSupport.java:73)
|
||||
at com.ankurm.hibernatedemo.testdb.DialectAndDdlTest.resolvedDialect(DialectAndDdlTest.java:23)
|
||||
at com.ankurm.hibernatedemo.testdb.DialectAndDdlTest.derby_resolvesDerbyDialect_fromTheCommunityDialectsModule_notHibernateCore(DialectAndDdlTest.java:65)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:701)
|
||||
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:502)
|
||||
at org.junit.jupiter.engine.support.MethodReflectionUtils.invoke(MethodReflectionUtils.java:45)
|
||||
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:61)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:124)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:163)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:148)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:123)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:105)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:99)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:66)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:47)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:39)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:104)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:98)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invokeVoid(InterceptingExecutableInvoker.java:71)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$0(TestMethodTestDescriptor.java:219)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:215)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:157)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:70)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:176)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:36)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:52)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:58)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.executeEngine(EngineExecutionOrchestrator.java:246)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.failOrExecuteEngine(EngineExecutionOrchestrator.java:218)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:179)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:66)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:157)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:65)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:125)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$2(InterceptingLauncher.java:57)
|
||||
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:56)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:125)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithCancellationToken(LauncherAdapter.java:68)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:54)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
|
||||
Caused by: java.sql.SQLSyntaxErrorException: 'DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.
|
||||
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:103)
|
||||
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Util.java:230)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(TransactionResourceImpl.java:431)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(TransactionResourceImpl.java:360)
|
||||
at org.apache.derby.impl.jdbc.EmbedConnection.handleException(EmbedConnection.java:2400)
|
||||
at org.apache.derby.impl.jdbc.ConnectionChild.handleException(ConnectionChild.java:86)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:697)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:637)
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:86)
|
||||
... 103 common frames omitted
|
||||
Caused by: ERROR 42Y55: 'DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:299)
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:294)
|
||||
at org.apache.derby.impl.sql.compile.DropSequenceNode.bindStatement(DropSequenceNode.java:74)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepMinion(GenericStatement.java:401)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepare(GenericStatement.java:99)
|
||||
at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(GenericLanguageConnectionContext.java:1114)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:689)
|
||||
... 105 common frames omitted
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
23:16:47.094 [main] INFO DEMO -- db=DERBY -> resolved dialect = org.hibernate.community.dialect.DerbyDialect
|
||||
Hibernate: drop table TestDbWidget
|
||||
Hibernate: drop sequence TestDbWidget_SEQ restrict
|
||||
23:16:47.144 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:16:47.149 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:h2:mem:testdb-pgmode;DB_CLOSE_DELAY=-1;MODE=PostgreSQL]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Default catalog/schema: TESTDB-PGMODE/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 100
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
Hibernate: create global temporary table HTE_TestDbWidget(active boolean, order integer, rn_ integer not null, sku varchar(5), id bigint, description clob, primary key (rn_)) transactional
|
||||
23:16:47.171 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
23:16:47.175 [main] INFO DEMO -- db=H2_POSTGRES_MODE -> resolved dialect = org.hibernate.dialect.H2Dialect
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
23:16:47.198 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:16:47.372 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:hsqldb:mem:testdb-plain]
|
||||
Database driver: HSQL Database Engine Driver
|
||||
Database dialect: HSQLDialect
|
||||
Database version: 2.7.3
|
||||
Default catalog/schema: PUBLIC/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: none
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
23:16:47.405 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence TestDbWidget_SEQ if exists
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
23:16:47.409 [main] INFO DEMO -- db=HSQLDB -> resolved dialect = org.hibernate.dialect.HSQLDialect
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence TestDbWidget_SEQ if exists
|
||||
23:16:47.424 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:16:47.428 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:h2:mem:testdb-oraclemode;DB_CLOSE_DELAY=-1;MODE=Oracle]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Default catalog/schema: TESTDB-ORACLEMODE/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 100
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
Hibernate: create global temporary table HTE_TestDbWidget(active boolean, order integer, rn_ integer not null, sku varchar(5), id bigint, description clob, primary key (rn_)) transactional
|
||||
23:16:47.453 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
23:16:47.458 [main] INFO DEMO -- db=H2_ORACLE_MODE -> resolved dialect = org.hibernate.dialect.H2Dialect
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
The failure as it actually appeared in a full 'mvn -B test' run of this repository,
|
||||
before hibernate.cache.use_second_level_cache was pinned to false in application.yml.
|
||||
It is order-dependent: running the two classes on their own passes.
|
||||
|
||||
[ERROR] ImmutableEntityTest.nativeSqlUpdate_onImmutableEntity_alwaysWorks:184 » Rollback Error while committing the transaction [Unable to perform afterTransactionCompletion callback: Cache[com.ank
|
||||
|
||||
[ERROR] Tests run: 140, Failures: 0, Errors: 1, Skipped: 0
|
||||
|
||||
Why every Spring context in the project had a second-level cache at all:
|
||||
$ mvn -o -B test -Dtest=JCacheOnClasspathAutoEnablesL2Test
|
||||
second-level cache enabled = true
|
||||
region factory = org.hibernate.cache.jcache.internal.JCacheRegionFactory
|
||||
explicitly configured? = true
|
||||
|
||||
Nothing in src/main/resources/application.yml mentions caching:
|
||||
$ grep -ic cache src/main/resources/application.yml
|
||||
0
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
# Quick survey: 22 candidate column names, tried unquoted against H2 2.4.240, HSQLDB 2.7.3, Derby 10.16.1.1
|
||||
# via a raw 'create table'. Looking for a word where the three engines actually diverge.
|
||||
|
||||
value: H2=FAIL HSQLDB=OK DERBY=OK
|
||||
key: H2=FAIL HSQLDB=OK DERBY=FAIL
|
||||
user: H2=FAIL HSQLDB=OK DERBY=FAIL
|
||||
size: H2=OK HSQLDB=OK DERBY=OK
|
||||
time: H2=OK HSQLDB=OK DERBY=OK
|
||||
date: H2=OK HSQLDB=OK DERBY=OK
|
||||
level: H2=OK HSQLDB=OK DERBY=OK
|
||||
row: H2=FAIL HSQLDB=OK DERBY=OK
|
||||
limit: H2=FAIL HSQLDB=OK DERBY=OK
|
||||
role: H2=OK HSQLDB=OK DERBY=OK
|
||||
count: H2=OK HSQLDB=OK DERBY=OK
|
||||
year: H2=FAIL HSQLDB=OK DERBY=FAIL
|
||||
type: H2=OK HSQLDB=OK DERBY=OK
|
||||
text: H2=OK HSQLDB=OK DERBY=OK
|
||||
data: H2=OK HSQLDB=OK DERBY=OK
|
||||
name: H2=OK HSQLDB=OK DERBY=OK
|
||||
number: H2=OK HSQLDB=OK DERBY=OK
|
||||
index: H2=OK HSQLDB=OK DERBY=OK
|
||||
state: H2=OK HSQLDB=OK DERBY=OK
|
||||
status: H2=OK HSQLDB=OK DERBY=OK
|
||||
group: H2=FAIL HSQLDB=FAIL DERBY=FAIL
|
||||
check: H2=FAIL HSQLDB=FAIL DERBY=FAIL
|
||||
Executable
+959
@@ -0,0 +1,959 @@
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/tmp/tools/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
23:22:21.650 [main] INFO org.hibernate.orm.core -- HHH000001: Hibernate ORM core version 7.4.5.Final
|
||||
23:22:21.953 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:22:22.150 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:h2:mem:testdb-timing0;DB_CLOSE_DELAY=-1]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Default catalog/schema: TESTDB-TIMING0/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 100
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
Hibernate: create global temporary table HTE_TestDbWidget(active boolean, order integer, rn_ integer not null, sku varchar(5), id bigint, description clob, primary key (rn_)) transactional
|
||||
23:22:23.166 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
23:22:23.235 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:22:23.240 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:h2:mem:testdb-timing1;DB_CLOSE_DELAY=-1]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Default catalog/schema: TESTDB-TIMING1/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 100
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
Hibernate: create global temporary table HTE_TestDbWidget(active boolean, order integer, rn_ integer not null, sku varchar(5), id bigint, description clob, primary key (rn_)) transactional
|
||||
23:22:23.289 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
23:22:23.304 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:22:23.310 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:h2:mem:testdb-timing2;DB_CLOSE_DELAY=-1]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Default catalog/schema: TESTDB-TIMING2/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 100
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
Hibernate: create global temporary table HTE_TestDbWidget(active boolean, order integer, rn_ integer not null, sku varchar(5), id bigint, description clob, primary key (rn_)) transactional
|
||||
23:22:23.351 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence if exists TestDbWidget_SEQ
|
||||
23:22:23.361 [main] INFO DEMO -- startup ms for H2 over 3 runs: 1628, 83, 62 (sandbox container -- indicative only, not a benchmark)
|
||||
23:22:23.377 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:22:23.545 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:hsqldb:mem:testdb-timing0]
|
||||
Database driver: HSQL Database Engine Driver
|
||||
Database dialect: HSQLDialect
|
||||
Database version: 2.7.3
|
||||
Default catalog/schema: PUBLIC/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: none
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
23:22:23.595 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence TestDbWidget_SEQ if exists
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence TestDbWidget_SEQ if exists
|
||||
23:22:23.614 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:22:23.632 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:hsqldb:mem:testdb-timing1]
|
||||
Database driver: HSQL Database Engine Driver
|
||||
Database dialect: HSQLDialect
|
||||
Database version: 2.7.3
|
||||
Default catalog/schema: PUBLIC/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: none
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
23:22:23.676 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence TestDbWidget_SEQ if exists
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence TestDbWidget_SEQ if exists
|
||||
23:22:23.694 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:22:23.728 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:hsqldb:mem:testdb-timing2]
|
||||
Database driver: HSQL Database Engine Driver
|
||||
Database dialect: HSQLDialect
|
||||
Database version: 2.7.3
|
||||
Default catalog/schema: PUBLIC/PUBLIC
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: none
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
23:22:23.754 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence TestDbWidget_SEQ if exists
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
Hibernate: drop table if exists TestDbWidget cascade
|
||||
Hibernate: drop sequence TestDbWidget_SEQ if exists
|
||||
23:22:23.757 [main] INFO DEMO -- startup ms for HSQLDB over 3 runs: 238, 79, 74 (sandbox container -- indicative only, not a benchmark)
|
||||
23:22:23.768 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:22:24.265 [main] WARN org.hibernate.orm.jdbc -- HHH100123: Low default JDBC fetch size: 1 (consider setting 'hibernate.jdbc.fetch_size')
|
||||
23:22:24.266 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:derby:memory:testdb-timing0;create=true]
|
||||
Database driver: Apache Derby Embedded JDBC Driver
|
||||
Database dialect: DerbyDialect
|
||||
Database version: 10.16.1
|
||||
Default catalog/schema: undefined/APP
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 1
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
23:22:24.301 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table TestDbWidget
|
||||
23:22:24.353 [main] WARN org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl -- GenerationTarget encountered exception accepting command : Error executing DDL "drop table TestDbWidget" via JDBC ['DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.]
|
||||
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "drop table TestDbWidget" via JDBC ['DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.]
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:91)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlString(Helper.java:218)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlStrings(Helper.java:204)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropTables(SchemaDropperImpl.java:376)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropConstraintsTablesSequences(SchemaDropperImpl.java:248)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:210)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:182)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:152)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:227)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$1(SchemaManagementToolCoordinator.java:101)
|
||||
at java.base/java.util.HashMap.forEach(HashMap.java:1430)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:100)
|
||||
at org.hibernate.boot.internal.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:35)
|
||||
at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:33)
|
||||
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:327)
|
||||
at org.hibernate.internal.SessionFactoryRegistry.instantiateSessionFactory(SessionFactoryRegistry.java:64)
|
||||
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:458)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:200)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:72)
|
||||
at com.ankurm.hibernatedemo.testdb.TestDbSupport.buildSessionFactory(TestDbSupport.java:73)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.timeOneBuild(StartupTimingTest.java:20)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.measureStartupAcrossThreeRunsPerDatabase(StartupTimingTest.java:32)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:701)
|
||||
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:502)
|
||||
at org.junit.jupiter.engine.support.MethodReflectionUtils.invoke(MethodReflectionUtils.java:45)
|
||||
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:61)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:124)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:163)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:148)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:123)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:105)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:99)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:66)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:47)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:39)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:104)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:98)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invokeVoid(InterceptingExecutableInvoker.java:71)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$0(TestMethodTestDescriptor.java:219)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:215)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:157)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:70)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:176)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:36)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:52)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:58)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.executeEngine(EngineExecutionOrchestrator.java:246)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.failOrExecuteEngine(EngineExecutionOrchestrator.java:218)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:179)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:66)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:157)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:65)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:125)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$2(InterceptingLauncher.java:57)
|
||||
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:56)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:125)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithCancellationToken(LauncherAdapter.java:68)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:54)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
|
||||
Caused by: java.sql.SQLSyntaxErrorException: 'DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.
|
||||
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:103)
|
||||
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Util.java:230)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(TransactionResourceImpl.java:431)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(TransactionResourceImpl.java:360)
|
||||
at org.apache.derby.impl.jdbc.EmbedConnection.handleException(EmbedConnection.java:2400)
|
||||
at org.apache.derby.impl.jdbc.ConnectionChild.handleException(ConnectionChild.java:86)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:697)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:637)
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:86)
|
||||
... 103 common frames omitted
|
||||
Caused by: ERROR 42Y55: 'DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:299)
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:294)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.justGetDescriptor(DDLStatementNode.java:366)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.getTableDescriptor(DDLStatementNode.java:337)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.getTableDescriptor(DDLStatementNode.java:289)
|
||||
at org.apache.derby.impl.sql.compile.DropTableNode.bindStatement(DropTableNode.java:98)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepMinion(GenericStatement.java:401)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepare(GenericStatement.java:99)
|
||||
at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(GenericLanguageConnectionContext.java:1114)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:689)
|
||||
... 105 common frames omitted
|
||||
Hibernate: drop sequence TestDbWidget_SEQ restrict
|
||||
23:22:24.359 [main] WARN org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl -- GenerationTarget encountered exception accepting command : Error executing DDL "drop sequence TestDbWidget_SEQ restrict" via JDBC ['DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.]
|
||||
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "drop sequence TestDbWidget_SEQ restrict" via JDBC ['DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.]
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:91)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlString(Helper.java:218)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlStrings(Helper.java:204)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropSequences(SchemaDropperImpl.java:335)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropConstraintsTablesSequences(SchemaDropperImpl.java:261)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:210)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:182)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:152)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:227)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$1(SchemaManagementToolCoordinator.java:101)
|
||||
at java.base/java.util.HashMap.forEach(HashMap.java:1430)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:100)
|
||||
at org.hibernate.boot.internal.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:35)
|
||||
at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:33)
|
||||
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:327)
|
||||
at org.hibernate.internal.SessionFactoryRegistry.instantiateSessionFactory(SessionFactoryRegistry.java:64)
|
||||
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:458)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:200)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:72)
|
||||
at com.ankurm.hibernatedemo.testdb.TestDbSupport.buildSessionFactory(TestDbSupport.java:73)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.timeOneBuild(StartupTimingTest.java:20)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.measureStartupAcrossThreeRunsPerDatabase(StartupTimingTest.java:32)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:701)
|
||||
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:502)
|
||||
at org.junit.jupiter.engine.support.MethodReflectionUtils.invoke(MethodReflectionUtils.java:45)
|
||||
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:61)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:124)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:163)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:148)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:123)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:105)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:99)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:66)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:47)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:39)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:104)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:98)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invokeVoid(InterceptingExecutableInvoker.java:71)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$0(TestMethodTestDescriptor.java:219)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:215)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:157)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:70)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:176)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:36)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:52)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:58)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.executeEngine(EngineExecutionOrchestrator.java:246)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.failOrExecuteEngine(EngineExecutionOrchestrator.java:218)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:179)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:66)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:157)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:65)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:125)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$2(InterceptingLauncher.java:57)
|
||||
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:56)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:125)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithCancellationToken(LauncherAdapter.java:68)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:54)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
|
||||
Caused by: java.sql.SQLSyntaxErrorException: 'DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.
|
||||
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:103)
|
||||
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Util.java:230)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(TransactionResourceImpl.java:431)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(TransactionResourceImpl.java:360)
|
||||
at org.apache.derby.impl.jdbc.EmbedConnection.handleException(EmbedConnection.java:2400)
|
||||
at org.apache.derby.impl.jdbc.ConnectionChild.handleException(ConnectionChild.java:86)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:697)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:637)
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:86)
|
||||
... 103 common frames omitted
|
||||
Caused by: ERROR 42Y55: 'DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:299)
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:294)
|
||||
at org.apache.derby.impl.sql.compile.DropSequenceNode.bindStatement(DropSequenceNode.java:74)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepMinion(GenericStatement.java:401)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepare(GenericStatement.java:99)
|
||||
at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(GenericLanguageConnectionContext.java:1114)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:689)
|
||||
... 105 common frames omitted
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
Hibernate: drop table TestDbWidget
|
||||
Hibernate: drop sequence TestDbWidget_SEQ restrict
|
||||
23:22:24.425 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:22:24.509 [main] WARN org.hibernate.orm.jdbc -- HHH100123: Low default JDBC fetch size: 1 (consider setting 'hibernate.jdbc.fetch_size')
|
||||
23:22:24.509 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:derby:memory:testdb-timing1;create=true]
|
||||
Database driver: Apache Derby Embedded JDBC Driver
|
||||
Database dialect: DerbyDialect
|
||||
Database version: 10.16.1
|
||||
Default catalog/schema: undefined/APP
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 1
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
23:22:24.562 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table TestDbWidget
|
||||
23:22:24.575 [main] WARN org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl -- GenerationTarget encountered exception accepting command : Error executing DDL "drop table TestDbWidget" via JDBC ['DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.]
|
||||
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "drop table TestDbWidget" via JDBC ['DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.]
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:91)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlString(Helper.java:218)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlStrings(Helper.java:204)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropTables(SchemaDropperImpl.java:376)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropConstraintsTablesSequences(SchemaDropperImpl.java:248)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:210)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:182)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:152)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:227)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$1(SchemaManagementToolCoordinator.java:101)
|
||||
at java.base/java.util.HashMap.forEach(HashMap.java:1430)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:100)
|
||||
at org.hibernate.boot.internal.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:35)
|
||||
at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:33)
|
||||
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:327)
|
||||
at org.hibernate.internal.SessionFactoryRegistry.instantiateSessionFactory(SessionFactoryRegistry.java:64)
|
||||
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:458)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:200)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:72)
|
||||
at com.ankurm.hibernatedemo.testdb.TestDbSupport.buildSessionFactory(TestDbSupport.java:73)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.timeOneBuild(StartupTimingTest.java:20)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.measureStartupAcrossThreeRunsPerDatabase(StartupTimingTest.java:32)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:701)
|
||||
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:502)
|
||||
at org.junit.jupiter.engine.support.MethodReflectionUtils.invoke(MethodReflectionUtils.java:45)
|
||||
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:61)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:124)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:163)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:148)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:123)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:105)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:99)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:66)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:47)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:39)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:104)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:98)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invokeVoid(InterceptingExecutableInvoker.java:71)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$0(TestMethodTestDescriptor.java:219)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:215)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:157)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:70)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:176)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:36)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:52)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:58)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.executeEngine(EngineExecutionOrchestrator.java:246)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.failOrExecuteEngine(EngineExecutionOrchestrator.java:218)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:179)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:66)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:157)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:65)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:125)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$2(InterceptingLauncher.java:57)
|
||||
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:56)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:125)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithCancellationToken(LauncherAdapter.java:68)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:54)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
|
||||
Caused by: java.sql.SQLSyntaxErrorException: 'DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.
|
||||
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:103)
|
||||
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Util.java:230)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(TransactionResourceImpl.java:431)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(TransactionResourceImpl.java:360)
|
||||
at org.apache.derby.impl.jdbc.EmbedConnection.handleException(EmbedConnection.java:2400)
|
||||
at org.apache.derby.impl.jdbc.ConnectionChild.handleException(ConnectionChild.java:86)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:697)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:637)
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:86)
|
||||
... 103 common frames omitted
|
||||
Caused by: ERROR 42Y55: 'DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:299)
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:294)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.justGetDescriptor(DDLStatementNode.java:366)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.getTableDescriptor(DDLStatementNode.java:337)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.getTableDescriptor(DDLStatementNode.java:289)
|
||||
at org.apache.derby.impl.sql.compile.DropTableNode.bindStatement(DropTableNode.java:98)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepMinion(GenericStatement.java:401)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepare(GenericStatement.java:99)
|
||||
at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(GenericLanguageConnectionContext.java:1114)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:689)
|
||||
... 105 common frames omitted
|
||||
Hibernate: drop sequence TestDbWidget_SEQ restrict
|
||||
23:22:24.581 [main] WARN org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl -- GenerationTarget encountered exception accepting command : Error executing DDL "drop sequence TestDbWidget_SEQ restrict" via JDBC ['DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.]
|
||||
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "drop sequence TestDbWidget_SEQ restrict" via JDBC ['DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.]
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:91)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlString(Helper.java:218)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlStrings(Helper.java:204)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropSequences(SchemaDropperImpl.java:335)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropConstraintsTablesSequences(SchemaDropperImpl.java:261)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:210)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:182)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:152)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:227)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$1(SchemaManagementToolCoordinator.java:101)
|
||||
at java.base/java.util.HashMap.forEach(HashMap.java:1430)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:100)
|
||||
at org.hibernate.boot.internal.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:35)
|
||||
at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:33)
|
||||
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:327)
|
||||
at org.hibernate.internal.SessionFactoryRegistry.instantiateSessionFactory(SessionFactoryRegistry.java:64)
|
||||
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:458)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:200)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:72)
|
||||
at com.ankurm.hibernatedemo.testdb.TestDbSupport.buildSessionFactory(TestDbSupport.java:73)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.timeOneBuild(StartupTimingTest.java:20)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.measureStartupAcrossThreeRunsPerDatabase(StartupTimingTest.java:32)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:701)
|
||||
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:502)
|
||||
at org.junit.jupiter.engine.support.MethodReflectionUtils.invoke(MethodReflectionUtils.java:45)
|
||||
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:61)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:124)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:163)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:148)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:123)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:105)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:99)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:66)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:47)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:39)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:104)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:98)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invokeVoid(InterceptingExecutableInvoker.java:71)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$0(TestMethodTestDescriptor.java:219)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:215)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:157)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:70)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:176)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:36)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:52)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:58)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.executeEngine(EngineExecutionOrchestrator.java:246)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.failOrExecuteEngine(EngineExecutionOrchestrator.java:218)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:179)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:66)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:157)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:65)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:125)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$2(InterceptingLauncher.java:57)
|
||||
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:56)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:125)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithCancellationToken(LauncherAdapter.java:68)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:54)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
|
||||
Caused by: java.sql.SQLSyntaxErrorException: 'DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.
|
||||
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:103)
|
||||
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Util.java:230)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(TransactionResourceImpl.java:431)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(TransactionResourceImpl.java:360)
|
||||
at org.apache.derby.impl.jdbc.EmbedConnection.handleException(EmbedConnection.java:2400)
|
||||
at org.apache.derby.impl.jdbc.ConnectionChild.handleException(ConnectionChild.java:86)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:697)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:637)
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:86)
|
||||
... 103 common frames omitted
|
||||
Caused by: ERROR 42Y55: 'DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:299)
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:294)
|
||||
at org.apache.derby.impl.sql.compile.DropSequenceNode.bindStatement(DropSequenceNode.java:74)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepMinion(GenericStatement.java:401)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepare(GenericStatement.java:99)
|
||||
at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(GenericLanguageConnectionContext.java:1114)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:689)
|
||||
... 105 common frames omitted
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
Hibernate: drop table TestDbWidget
|
||||
Hibernate: drop sequence TestDbWidget_SEQ restrict
|
||||
23:22:24.607 [main] WARN org.hibernate.orm.connections.pooling -- HHH10001002: Using built-in connection pool (not intended for production use)
|
||||
23:22:24.686 [main] WARN org.hibernate.orm.jdbc -- HHH100123: Low default JDBC fetch size: 1 (consider setting 'hibernate.jdbc.fetch_size')
|
||||
23:22:24.686 [main] INFO org.hibernate.orm.connections.pooling -- HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:derby:memory:testdb-timing2;create=true]
|
||||
Database driver: Apache Derby Embedded JDBC Driver
|
||||
Database dialect: DerbyDialect
|
||||
Database version: 10.16.1
|
||||
Default catalog/schema: undefined/APP
|
||||
Autocommit mode: false
|
||||
Isolation level: READ_COMMITTED
|
||||
JDBC fetch size: 1
|
||||
Pool: DriverManagerConnectionProvider
|
||||
Minimum pool size: 1
|
||||
Maximum pool size: 20
|
||||
23:22:24.709 [main] INFO org.hibernate.orm.core -- HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
Hibernate: drop table TestDbWidget
|
||||
23:22:24.710 [main] WARN org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl -- GenerationTarget encountered exception accepting command : Error executing DDL "drop table TestDbWidget" via JDBC ['DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.]
|
||||
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "drop table TestDbWidget" via JDBC ['DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.]
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:91)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlString(Helper.java:218)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlStrings(Helper.java:204)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropTables(SchemaDropperImpl.java:376)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropConstraintsTablesSequences(SchemaDropperImpl.java:248)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:210)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:182)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:152)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:227)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$1(SchemaManagementToolCoordinator.java:101)
|
||||
at java.base/java.util.HashMap.forEach(HashMap.java:1430)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:100)
|
||||
at org.hibernate.boot.internal.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:35)
|
||||
at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:33)
|
||||
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:327)
|
||||
at org.hibernate.internal.SessionFactoryRegistry.instantiateSessionFactory(SessionFactoryRegistry.java:64)
|
||||
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:458)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:200)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:72)
|
||||
at com.ankurm.hibernatedemo.testdb.TestDbSupport.buildSessionFactory(TestDbSupport.java:73)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.timeOneBuild(StartupTimingTest.java:20)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.measureStartupAcrossThreeRunsPerDatabase(StartupTimingTest.java:32)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:701)
|
||||
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:502)
|
||||
at org.junit.jupiter.engine.support.MethodReflectionUtils.invoke(MethodReflectionUtils.java:45)
|
||||
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:61)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:124)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:163)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:148)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:123)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:105)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:99)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:66)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:47)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:39)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:104)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:98)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invokeVoid(InterceptingExecutableInvoker.java:71)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$0(TestMethodTestDescriptor.java:219)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:215)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:157)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:70)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:176)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:36)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:52)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:58)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.executeEngine(EngineExecutionOrchestrator.java:246)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.failOrExecuteEngine(EngineExecutionOrchestrator.java:218)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:179)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:66)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:157)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:65)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:125)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$2(InterceptingLauncher.java:57)
|
||||
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:56)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:125)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithCancellationToken(LauncherAdapter.java:68)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:54)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
|
||||
Caused by: java.sql.SQLSyntaxErrorException: 'DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.
|
||||
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:103)
|
||||
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Util.java:230)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(TransactionResourceImpl.java:431)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(TransactionResourceImpl.java:360)
|
||||
at org.apache.derby.impl.jdbc.EmbedConnection.handleException(EmbedConnection.java:2400)
|
||||
at org.apache.derby.impl.jdbc.ConnectionChild.handleException(ConnectionChild.java:86)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:697)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:637)
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:86)
|
||||
... 103 common frames omitted
|
||||
Caused by: ERROR 42Y55: 'DROP TABLE' cannot be performed on 'TESTDBWIDGET' because it does not exist.
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:299)
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:294)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.justGetDescriptor(DDLStatementNode.java:366)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.getTableDescriptor(DDLStatementNode.java:337)
|
||||
at org.apache.derby.impl.sql.compile.DDLStatementNode.getTableDescriptor(DDLStatementNode.java:289)
|
||||
at org.apache.derby.impl.sql.compile.DropTableNode.bindStatement(DropTableNode.java:98)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepMinion(GenericStatement.java:401)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepare(GenericStatement.java:99)
|
||||
at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(GenericLanguageConnectionContext.java:1114)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:689)
|
||||
... 105 common frames omitted
|
||||
Hibernate: drop sequence TestDbWidget_SEQ restrict
|
||||
23:22:24.712 [main] WARN org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl -- GenerationTarget encountered exception accepting command : Error executing DDL "drop sequence TestDbWidget_SEQ restrict" via JDBC ['DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.]
|
||||
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "drop sequence TestDbWidget_SEQ restrict" via JDBC ['DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.]
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:91)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlString(Helper.java:218)
|
||||
at org.hibernate.tool.schema.internal.Helper.applySqlStrings(Helper.java:204)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropSequences(SchemaDropperImpl.java:335)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropConstraintsTablesSequences(SchemaDropperImpl.java:261)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:210)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:182)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:152)
|
||||
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:112)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:227)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$1(SchemaManagementToolCoordinator.java:101)
|
||||
at java.base/java.util.HashMap.forEach(HashMap.java:1430)
|
||||
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:100)
|
||||
at org.hibernate.boot.internal.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:35)
|
||||
at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:33)
|
||||
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:327)
|
||||
at org.hibernate.internal.SessionFactoryRegistry.instantiateSessionFactory(SessionFactoryRegistry.java:64)
|
||||
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:458)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:200)
|
||||
at org.hibernate.boot.internal.MetadataImpl.buildSessionFactory(MetadataImpl.java:72)
|
||||
at com.ankurm.hibernatedemo.testdb.TestDbSupport.buildSessionFactory(TestDbSupport.java:73)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.timeOneBuild(StartupTimingTest.java:20)
|
||||
at com.ankurm.hibernatedemo.testdb.StartupTimingTest.measureStartupAcrossThreeRunsPerDatabase(StartupTimingTest.java:32)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:701)
|
||||
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:502)
|
||||
at org.junit.jupiter.engine.support.MethodReflectionUtils.invoke(MethodReflectionUtils.java:45)
|
||||
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:61)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:124)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:163)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:148)
|
||||
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:123)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:105)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:99)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:66)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:47)
|
||||
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:39)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:104)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:98)
|
||||
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invokeVoid(InterceptingExecutableInvoker.java:71)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$0(TestMethodTestDescriptor.java:219)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:215)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:157)
|
||||
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:70)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:176)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:42)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$2(NodeTestTask.java:180)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$1(NodeTestTask.java:166)
|
||||
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:138)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$0(NodeTestTask.java:164)
|
||||
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:74)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:163)
|
||||
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:116)
|
||||
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:36)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:52)
|
||||
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:58)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.executeEngine(EngineExecutionOrchestrator.java:246)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.failOrExecuteEngine(EngineExecutionOrchestrator.java:218)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:179)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:66)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:157)
|
||||
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:65)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:125)
|
||||
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$2(InterceptingLauncher.java:57)
|
||||
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
|
||||
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:56)
|
||||
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:58)
|
||||
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
|
||||
at java.base/java.lang.reflect.Method.invoke(Method.java:565)
|
||||
at org.apache.maven.surefire.api.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:125)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithCancellationToken(LauncherAdapter.java:68)
|
||||
at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:54)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168)
|
||||
at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
|
||||
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
|
||||
Caused by: java.sql.SQLSyntaxErrorException: 'DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.
|
||||
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:103)
|
||||
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Util.java:230)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(TransactionResourceImpl.java:431)
|
||||
at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(TransactionResourceImpl.java:360)
|
||||
at org.apache.derby.impl.jdbc.EmbedConnection.handleException(EmbedConnection.java:2400)
|
||||
at org.apache.derby.impl.jdbc.ConnectionChild.handleException(ConnectionChild.java:86)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:697)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:637)
|
||||
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:86)
|
||||
... 103 common frames omitted
|
||||
Caused by: ERROR 42Y55: 'DROP TESTDBWIDGET_SEQ' cannot be performed on 'TESTDBWIDGET_SEQ' because it does not exist.
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:299)
|
||||
at org.apache.derby.shared.common.error.StandardException.newException(StandardException.java:294)
|
||||
at org.apache.derby.impl.sql.compile.DropSequenceNode.bindStatement(DropSequenceNode.java:74)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepMinion(GenericStatement.java:401)
|
||||
at org.apache.derby.impl.sql.GenericStatement.prepare(GenericStatement.java:99)
|
||||
at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(GenericLanguageConnectionContext.java:1114)
|
||||
at org.apache.derby.impl.jdbc.EmbedStatement.execute(EmbedStatement.java:689)
|
||||
... 105 common frames omitted
|
||||
Hibernate: create sequence TestDbWidget_SEQ start with 1 increment by 50
|
||||
Hibernate: create table TestDbWidget (active boolean not null, "order" integer, sku varchar(5), id bigint not null, description clob, primary key (id))
|
||||
Hibernate: drop table TestDbWidget
|
||||
Hibernate: drop sequence TestDbWidget_SEQ restrict
|
||||
23:22:24.728 [main] INFO DEMO -- startup ms for DERBY over 3 runs: 637, 176, 125 (sandbox container -- indicative only, not a benchmark)
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
# Startup timing: SessionFactory build time (nanoTime, ms), 3 runs per database.
|
||||
# Measured in a shared sandbox container -- NOT a benchmark, indicative of relative order of
|
||||
# magnitude only. The first H2 run includes JVM/driver class-loading overhead common to
|
||||
# whichever database happens to run first in the JVM.
|
||||
|
||||
23:22:23.361 [main] INFO DEMO -- startup ms for H2 over 3 runs: 1628, 83, 62 (sandbox container -- indicative only, not a benchmark)
|
||||
23:22:23.757 [main] INFO DEMO -- startup ms for HSQLDB over 3 runs: 238, 79, 74 (sandbox container -- indicative only, not a benchmark)
|
||||
23:22:24.728 [main] INFO DEMO -- startup ms for DERBY over 3 runs: 637, 176, 125 (sandbox container -- indicative only, not a benchmark)
|
||||
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>4.1.1</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.ankurm</groupId>
|
||||
<artifactId>hibernate-demo</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<name>hibernate-demo</name>
|
||||
<description>
|
||||
Companion repository for the ankurm.com Hibernate 7 batch: get() vs load(), merge() vs
|
||||
refresh(), and inserting objects efficiently.
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<java.version>25</java.version>
|
||||
<!--
|
||||
Spring Boot 4.1.0's own dependency management already resolves hibernate.version to
|
||||
7.4.1.Final (checked in spring-boot-dependencies-4.1.0.pom before writing a line of code
|
||||
here). This property is declared anyway, not to override anything, but so the pin is
|
||||
visible in the POM and survives a future Boot patch release quietly bumping it under us.
|
||||
See docs/00-versions.md for the two Boot releases (4.1.0 and 4.1.1) that resolve to two
|
||||
different Hibernate patch versions from the same "4.1" line.
|
||||
-->
|
||||
<hibernate.version>7.4.5.Final</hibernate.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derby</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derbytools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.h-thurow</groupId>
|
||||
<artifactId>simple-jndi</artifactId>
|
||||
<version>0.25.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tools.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.orm</groupId>
|
||||
<artifactId>hibernate-jcache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.cache</groupId>
|
||||
<artifactId>cache-api</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>3.10.8</version>
|
||||
<classifier>jakarta</classifier>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.orm</groupId>
|
||||
<artifactId>hibernate-community-dialects</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,38 @@
|
||||
import re, sys, os
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
DOCS = os.path.join(ROOT, "docs")
|
||||
|
||||
link_re = re.compile(r'\[[^\]]*\]\(([^)]+)\)')
|
||||
|
||||
errors = []
|
||||
checked = 0
|
||||
|
||||
for dirpath, _, filenames in os.walk(DOCS):
|
||||
for fn in filenames:
|
||||
if not fn.endswith(".md"):
|
||||
continue
|
||||
path = os.path.join(dirpath, fn)
|
||||
with open(path, encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
for m in link_re.finditer(content):
|
||||
target = m.group(1).strip()
|
||||
if target.startswith(("http://", "https://", "mailto:")):
|
||||
continue
|
||||
# strip fragment
|
||||
target_path = target.split("#", 1)[0]
|
||||
if not target_path:
|
||||
continue
|
||||
resolved = os.path.normpath(os.path.join(dirpath, target_path))
|
||||
checked += 1
|
||||
if not os.path.exists(resolved):
|
||||
errors.append(f"{os.path.relpath(path, ROOT)}: broken link -> {target} (resolved: {os.path.relpath(resolved, ROOT)})")
|
||||
|
||||
print(f"Checked {checked} relative links across docs/*.md")
|
||||
if errors:
|
||||
print(f"\n{len(errors)} BROKEN LINK(S):")
|
||||
for e in errors:
|
||||
print(" " + e)
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("All relative links resolve to existing files.")
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Turn a raw mvn spring-boot:run capture into a clean, reproducible transcript.
|
||||
|
||||
Strips JVM/build noise (sun.misc.Unsafe warnings, JAVA_TOOL_OPTIONS proxy banners) and the
|
||||
duplicate un-prefixed echo of each SQL statement that org.hibernate.SQL's show_sql=true prints
|
||||
to stdout in addition to the "Hibernate: ..." line the logger emits -- same text twice, so only
|
||||
the logger-prefixed copy is kept.
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
|
||||
DROP_PREFIXES = (
|
||||
"WARNING:",
|
||||
"Picked up JAVA_TOOL_OPTIONS",
|
||||
)
|
||||
|
||||
|
||||
def clean(lines):
|
||||
out = []
|
||||
for line in lines:
|
||||
stripped = line.rstrip("\n")
|
||||
if any(stripped.startswith(p) for p in DROP_PREFIXES):
|
||||
continue
|
||||
# Drop the bare SQL echo line that show_sql=true prints without the "Hibernate: " prefix
|
||||
# -- it is always immediately followed by the same text WITH the prefix.
|
||||
out.append(stripped)
|
||||
deduped = []
|
||||
i = 0
|
||||
while i < len(out):
|
||||
cur = out[i]
|
||||
nxt = out[i + 1] if i + 1 < len(out) else None
|
||||
if nxt is not None and nxt == "Hibernate: " + cur:
|
||||
i += 1 # skip the bare echo, keep the prefixed one on the next iteration
|
||||
continue
|
||||
deduped.append(out[i])
|
||||
i += 1
|
||||
return deduped
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
src, dst = sys.argv[1], sys.argv[2]
|
||||
with open(src, encoding="utf-8") as f:
|
||||
lines = f.readlines()
|
||||
cleaned = clean(lines)
|
||||
with open(dst, "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(cleaned) + "\n")
|
||||
print(f"{src}: {len(lines)} -> {dst}: {len(cleaned)} lines")
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
# Regenerate every file in docs/output/ from a real run. This is the script referenced by
|
||||
# "regenerated by one command" in the post and the README -- if it stops producing the same
|
||||
# shape of output, the docs are wrong until it's fixed, not the other way around.
|
||||
set -eu
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
RAW_DIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$RAW_DIR"' EXIT
|
||||
|
||||
run_one() {
|
||||
local profile="$1" outfile="$2"
|
||||
echo "=== running profile: $profile ===" >&2
|
||||
mvn -q -B org.springframework.boot:spring-boot-maven-plugin:run \
|
||||
-Dspring-boot.run.profiles="$profile" 2>&1 \
|
||||
| grep -v '^Picked up JAVA_TOOL_OPTIONS' \
|
||||
| grep -v '^WARNING:' \
|
||||
> "$RAW_DIR/$profile.raw.txt"
|
||||
python3 scripts/clean_output.py "$RAW_DIR/$profile.raw.txt" "docs/output/$outfile"
|
||||
}
|
||||
|
||||
run_one getvsload get-vs-load.txt
|
||||
run_one mergerefresh merge-vs-refresh.txt
|
||||
run_one insert-identity insert-identity.txt
|
||||
run_one insert-sequence insert-sequence.txt
|
||||
|
||||
echo "docs/output/ regenerated." >&2
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run one scenario in the foreground and exit.
|
||||
#
|
||||
# ./scripts/run.sh getvsload
|
||||
# ./scripts/run.sh mergerefresh
|
||||
# ./scripts/run.sh insert-identity
|
||||
# ./scripts/run.sh insert-sequence
|
||||
#
|
||||
# Every scenario here is a CommandLineRunner against an in-memory H2 database with
|
||||
# spring.main.web-application-type=none, so there is no server to keep alive and nothing to
|
||||
# kill afterwards -- the process runs the scenario and exits on its own.
|
||||
set -eu
|
||||
|
||||
PROFILE="${1:?usage: run.sh <getvsload|mergerefresh|insert-identity|insert-sequence>}"
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
mvn -q -B org.springframework.boot:spring-boot-maven-plugin:run \
|
||||
-Dspring-boot.run.profiles="$PROFILE"
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.ankurm.hibernatedemo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* Entry point for the companion demos behind three ankurm.com Hibernate 7 posts:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@code get-vs-load} — docs/01-get-vs-load.md, {@link com.ankurm.hibernatedemo.scenario.GetVsLoadRunner}</li>
|
||||
* <li>{@code merge-vs-refresh} — docs/02-merge-vs-refresh.md, {@link com.ankurm.hibernatedemo.scenario.MergeVsRefreshRunner}</li>
|
||||
* <li>{@code insert-identity} / {@code insert-sequence} — docs/03-inserting-objects.md,
|
||||
* {@link com.ankurm.hibernatedemo.scenario.InsertIdentityRunner} and
|
||||
* {@link com.ankurm.hibernatedemo.scenario.InsertSequenceRunner}</li>
|
||||
* </ul>
|
||||
*
|
||||
* Each scenario is a profile-gated {@link org.springframework.boot.CommandLineRunner} that runs
|
||||
* once against an in-memory H2 database and exits — there is no web server to keep alive,
|
||||
* so {@code scripts/run.sh <profile>} is a plain foreground {@code mvn spring-boot:run} call.
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class HibernateDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(HibernateDemoApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.NamedEntityGraph;
|
||||
import jakarta.persistence.NamedAttributeNode;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Plain (non-batched) author used for the N+1 / fetch-join / entity-graph comparison in
|
||||
* docs/12-association-mappings.md, chapter "Counting the N+1". No {@code @BatchSize} here on
|
||||
* purpose — {@link BatchAuthor} is the batched twin used for the fourth number.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "assoc_author")
|
||||
@NamedEntityGraph(name = "AssocAuthor.books", attributeNodes = @NamedAttributeNode("books"))
|
||||
public class AssocAuthor {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "author", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
|
||||
private List<AssocBook> books = new ArrayList<>();
|
||||
|
||||
protected AssocAuthor() {
|
||||
}
|
||||
|
||||
public AssocAuthor(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<AssocBook> getBooks() {
|
||||
return books;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
/** Owning side (holds the FK) of {@link AssocAuthor#getBooks()}. Docs: 12-association-mappings.md. */
|
||||
@Entity
|
||||
@Table(name = "assoc_book")
|
||||
public class AssocBook {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "author_id")
|
||||
private AssocAuthor author;
|
||||
|
||||
protected AssocBook() {
|
||||
}
|
||||
|
||||
public AssocBook(String title, AssocAuthor author) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public AssocAuthor getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(AssocAuthor author) {
|
||||
this.author = author;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Deliberately has TWO {@code List} (bag) collections so that fetch-joining both in one JPQL
|
||||
* query reproduces {@code org.hibernate.loader.MultipleBagFetchException}. Docs: 12-association-mappings.md,
|
||||
* chapter "MultipleBagFetchException".
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "bag_author_list")
|
||||
public class BagAuthorList {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "author", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
|
||||
private List<BagBookL> books = new ArrayList<>();
|
||||
|
||||
@OneToMany(mappedBy = "author", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
|
||||
private List<BagAwardL> awards = new ArrayList<>();
|
||||
|
||||
protected BagAuthorList() {
|
||||
}
|
||||
|
||||
public BagAuthorList(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<BagBookL> getBooks() {
|
||||
return books;
|
||||
}
|
||||
|
||||
public List<BagAwardL> getAwards() {
|
||||
return awards;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Same shape as {@link BagAuthorList} but with {@code Set} collections — fetch-joining
|
||||
* both does NOT throw {@code MultipleBagFetchException} (that is Fix #1), but it does reproduce
|
||||
* the cartesian-product row explosion: one SQL row per (book, award) pair per author.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "bag_author_set")
|
||||
public class BagAuthorSet {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "author", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
|
||||
private Set<BagBookS> books = new HashSet<>();
|
||||
|
||||
@OneToMany(mappedBy = "author", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
|
||||
private Set<BagAwardS> awards = new HashSet<>();
|
||||
|
||||
protected BagAuthorSet() {
|
||||
}
|
||||
|
||||
public BagAuthorSet(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Set<BagBookS> getBooks() {
|
||||
return books;
|
||||
}
|
||||
|
||||
public Set<BagAwardS> getAwards() {
|
||||
return awards;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "bag_award_l")
|
||||
public class BagAwardL {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "author_id")
|
||||
private BagAuthorList author;
|
||||
|
||||
protected BagAwardL() {
|
||||
}
|
||||
|
||||
public BagAwardL(String name, BagAuthorList author) {
|
||||
this.name = name;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "bag_award_s")
|
||||
public class BagAwardS {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "author_id")
|
||||
private BagAuthorSet author;
|
||||
|
||||
protected BagAwardS() {
|
||||
}
|
||||
|
||||
public BagAwardS(String name, BagAuthorSet author) {
|
||||
this.name = name;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "bag_book_l")
|
||||
public class BagBookL {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "author_id")
|
||||
private BagAuthorList author;
|
||||
|
||||
protected BagBookL() {
|
||||
}
|
||||
|
||||
public BagBookL(String title, BagAuthorList author) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "bag_book_s")
|
||||
public class BagBookS {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "author_id")
|
||||
private BagAuthorSet author;
|
||||
|
||||
protected BagBookS() {
|
||||
}
|
||||
|
||||
public BagBookS(String title, BagAuthorSet author) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.hibernate.annotations.BatchSize;
|
||||
|
||||
/**
|
||||
* Same shape as {@link AssocAuthor} but the {@code books} collection carries
|
||||
* {@code @BatchSize(size = 10)} — the fourth number in the N+1 comparison table.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "batch_author")
|
||||
public class BatchAuthor {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@BatchSize(size = 10)
|
||||
@OneToMany(mappedBy = "author", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
|
||||
private List<BatchBook> books = new ArrayList<>();
|
||||
|
||||
protected BatchAuthor() {
|
||||
}
|
||||
|
||||
public BatchAuthor(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<BatchBook> getBooks() {
|
||||
return books;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "batch_book")
|
||||
public class BatchBook {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "author_id")
|
||||
private BatchAuthor author;
|
||||
|
||||
protected BatchBook() {
|
||||
}
|
||||
|
||||
public BatchBook(String title, BatchAuthor author) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@code cascade = ALL, orphanRemoval = true}: the "developer did not expect this" cascade
|
||||
* trap. Docs: 12-association-mappings.md, chapter "Cascade and orphanRemoval".
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "cascade_author")
|
||||
public class CascadeAuthor {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
private List<CascadeBook> books = new ArrayList<>();
|
||||
|
||||
protected CascadeAuthor() {
|
||||
}
|
||||
|
||||
public CascadeAuthor(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<CascadeBook> getBooks() {
|
||||
return books;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bug: a developer "resets" the list by assigning a brand new collection instead of
|
||||
* mutating the existing one (a common pattern when mapping from a DTO). With
|
||||
* {@code orphanRemoval = true}, Hibernate sees every previously-owned book missing from the
|
||||
* new collection and deletes all of them on flush.
|
||||
*/
|
||||
public void replaceBooksWithNewList(List<CascadeBook> newBooks) {
|
||||
this.books = new ArrayList<>(newBooks);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "cascade_book")
|
||||
public class CascadeBook {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "author_id")
|
||||
private CascadeAuthor author;
|
||||
|
||||
protected CascadeBook() {
|
||||
}
|
||||
|
||||
public CascadeBook(String title, CascadeAuthor author) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
/** Owning side (holds {@code user_id} FK) of {@link LazyUser#getProfile()}. */
|
||||
@Entity
|
||||
@Table(name = "lazy_profile")
|
||||
public class LazyProfile {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String bio;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "user_id")
|
||||
private LazyUser user;
|
||||
|
||||
protected LazyProfile() {
|
||||
}
|
||||
|
||||
public LazyProfile(String bio, LazyUser user) {
|
||||
this.bio = bio;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
/**
|
||||
* Non-owning ("mappedBy") side of an optional {@code @OneToOne}. Docs: 12-association-mappings.md,
|
||||
* chapter "The @OneToOne lazy trap". Even though {@link #profile} is declared
|
||||
* {@code FetchType.LAZY}, Hibernate cannot build a proxy for it here without bytecode
|
||||
* enhancement: it does not hold the foreign key, so it cannot know whether a profile row
|
||||
* exists without querying. The result is an eager extra SELECT on every load of LazyUser.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "lazy_user")
|
||||
public class LazyUser {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String username;
|
||||
|
||||
@OneToOne(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL, optional = true)
|
||||
private LazyProfile profile;
|
||||
|
||||
protected LazyUser() {
|
||||
}
|
||||
|
||||
public LazyUser(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public LazyProfile getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void setProfile(LazyProfile profile) {
|
||||
this.profile = profile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.MapsId;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
/** Owning side using {@code @MapsId}: its {@code @Id} IS the {@code user_id} FK value. */
|
||||
@Entity
|
||||
@Table(name = "mi_profile")
|
||||
public class MiProfile {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String bio;
|
||||
|
||||
@MapsId
|
||||
@OneToOne
|
||||
@JoinColumn(name = "id")
|
||||
private MiUser user;
|
||||
|
||||
protected MiProfile() {
|
||||
}
|
||||
|
||||
public MiProfile(String bio, MiUser user) {
|
||||
this.bio = bio;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
/**
|
||||
* The @MapsId fix: this entity carries NO inverse {@code @OneToOne} field at all. A profile is
|
||||
* looked up on demand with {@code session.find(MiProfile.class, userId)} because it shares the
|
||||
* same primary key value as the user (see {@link MiProfile}), so there is nothing to proxy and
|
||||
* nothing forces an eager join when loading a user.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "mi_user")
|
||||
public class MiUser {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String username;
|
||||
|
||||
protected MiUser() {
|
||||
}
|
||||
|
||||
public MiUser(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@code cascade = {PERSIST, MERGE}}, no {@code orphanRemoval}. Used for two things:
|
||||
* (1) removing a child from the in-memory collection and flushing does nothing to the row
|
||||
* (docs: "orphanRemoval off"), and (2) mutating only this inverse side (the collection) without
|
||||
* touching {@link NoOrphanBook#setAuthor} never writes the FK (docs: "owning side").
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "no_orphan_author")
|
||||
public class NoOrphanAuthor {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "author", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
|
||||
private List<NoOrphanBook> books = new ArrayList<>();
|
||||
|
||||
protected NoOrphanAuthor() {
|
||||
}
|
||||
|
||||
public NoOrphanAuthor(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<NoOrphanBook> getBooks() {
|
||||
return books;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.ankurm.hibernatedemo.association;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "no_orphan_book")
|
||||
public class NoOrphanBook {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "author_id")
|
||||
private NoOrphanAuthor author;
|
||||
|
||||
protected NoOrphanBook() {
|
||||
}
|
||||
|
||||
public NoOrphanBook(String title, NoOrphanAuthor author) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public NoOrphanAuthor getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(NoOrphanAuthor author) {
|
||||
this.author = author;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.ankurm.hibernatedemo.datetime;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** Docs: 13-date-and-time-mapping.md, chapter "Second-precision / truncation". */
|
||||
@Entity
|
||||
@Table(name = "nano_precision")
|
||||
public class NanoPrecisionEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private LocalDateTime plainLocalDateTime;
|
||||
|
||||
@Column(precision = 9)
|
||||
private LocalDateTime highPrecisionLocalDateTime;
|
||||
|
||||
private Instant plainInstant;
|
||||
|
||||
protected NanoPrecisionEntity() {
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public LocalDateTime getPlainLocalDateTime() {
|
||||
return plainLocalDateTime;
|
||||
}
|
||||
|
||||
public void setPlainLocalDateTime(LocalDateTime v) {
|
||||
this.plainLocalDateTime = v;
|
||||
}
|
||||
|
||||
public LocalDateTime getHighPrecisionLocalDateTime() {
|
||||
return highPrecisionLocalDateTime;
|
||||
}
|
||||
|
||||
public void setHighPrecisionLocalDateTime(LocalDateTime v) {
|
||||
this.highPrecisionLocalDateTime = v;
|
||||
}
|
||||
|
||||
public Instant getPlainInstant() {
|
||||
return plainInstant;
|
||||
}
|
||||
|
||||
public void setPlainInstant(Instant v) {
|
||||
this.plainInstant = v;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user