# Technical Documentation: hibernate/hibernate-orm

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/hibernate/hibernate-orm)

### Overview (`ci/tck-readme.md`)

Platform-tck build instructions
===============================

info: https://github.com/jakartaee/platform-tck/wiki/Instructions-for-building-and-running-JakartaEE-TCK-bundle

* Clone https://github.com/jakartaee/platform-tck

* Set env. variables:
  * export WORKSPACE=/directory/where/jakartaee-tck/was/cloned
  * export GF_BUNDLE_URL=https://ci.eclipse.org/jakartaee-tck/job/build-glassfish/lastSuccessfulBuild/artifact/appserver/distributions/glassfish/target/glassfish.zip
  * export ANT_HOME=/path/to/apache-ant (1.10.5+)
  * export JAVA_HOME=/path/to/jdk (11+)
  * export PATH=$JAVA_HOME/bin:$ANT_HOME/bin/:$PATH

* Run the following cmd from the root of the repo: 
  <code>$WORKSPACE/docker/build_standalone-tcks.sh jpa</code>

* If all goes well, this should generate a zip file called persistence-tck-3.1.0_\<date>.zip inside the <code>$WORKSPACE/release/jpa_build/build_\<date>/bundle/persistence-tck</code> folder. This can then be used to build and run the hibernate jakarta-tck-runner image.

---

### Overview (`docker-compose/README.md`)

# DB containers

Describes the approach of managing DB containers.

Starting DBs relies on the Docker (Podman) compose, driven through the [`db.sh`](../db.sh)
script at the root of the repository (run `./db.sh` with no arguments, or with `-h`, to list
all the supported DBs/versions).

## Directory structure

* [build-config](build-config): contains Dockerfiles for custom-built images like EDB
 or additional config files that are "mounted" to the corresponding DBs
* [latest](latest): contains a set of compose files with the latest versions of DBs.
 Each subdirectory is monitored by Dependabot (see `.github/dependabot.yml`), and PRs
 will be opened automatically when a new image is available.
* [versioned](versioned): contains compose files for previous versions of DBs,
 the ones that we are not testing as regularly as the latest ones.

Each DB's compose file lives in its own subdirectory (e.g. `latest/mariadb/docker-compose.yaml`,
`versioned/mariadb-12-1/docker-compose.yaml`), named `<db>-<major>-<minor>` for versioned ones.
The image is referenced through an env var with a default value pinned to a specific tag
and `@sha256` digest, e.g. `${MARIADB_IMAGE:-docker.io/library/mariadb:13.0@sha256:...}` in
`latest`, and `${DB_IMAGE_MARIADB_12_1:-docker.io/library/mariadb:12.1@sha256:...}` in `versioned`.
Pinning the digest keeps runs reproducible; Dependabot (for `latest`) or the person adding the
versioned file (for `versioned`) is responsible for resolving the digest for a new tag.

## Adding a brand-new DB

1. Add a new compose file under `latest/<db>/docker-compose.yaml`.
2. Always add a healthcheck that succeeds only when the DB is fully ready to accept requests.
   If the image doesn't have the tools required to implement the healthcheck itself,
   use the sidecar approach applied in [`latest/spanner/docker-compose.yaml`](latest/spanner/docker-compose.yaml).
3. Register the new `latest/<db>` directory under the `docker-compose` entry in
   [`.github/dependabot.yml`](../.github/dependabot.yml) so future image updates are picked up
   automatically. Directories are listed explicitly there; a new DB is invisible to Dependabot
   until it's added to that list.
4. Add the corresponding functions to [`db.sh`](../db.sh): a `<db>()` entry point that starts
   the latest version, and list it in the usage/help output near the bottom of the script.
5. If the DB should run in CI, add it to the test matrix in `.github/workflows/ci.yml`.

## Adding a new version of an existing DB

Dependabot opens PRs that bump the image in `latest/<db>/docker-compose.yaml` automatically.
Most of these bumps only refresh the image digest for the *same* tag (e.g. a rebuild of
`postgis:18-3.6`) or move a patch version (e.g. `cockroachdb:v26.3.1` -> `v26.3.2`); those can
be merged as-is, no further action needed.

When a bump instead moves to a genuinely new version (a new major/minor line, e.g.
MariaDB `12.3` -> `13.0`), and you want to keep the old version testable, do the following
*before* merging the Dependabot bump (or as a follow-up to it):

1. Create `versioned/<db>-<old-major>-<old-minor>/docker-compose.yaml` with the contents
   `latest/<db>/docker-compose.yaml` had *before* the bump, i.e. still pinned to the old
   image tag and digest. Switch its env var override to a version-specific name
   (e.g. `DB_IMAGE_MARIADB_12_3`) so it doesn't collide with the `latest` one.
2. In [`db.sh`](../db.sh), add a `<db>_<old-major>_<old-minor>()` function that starts the
   new versioned compose file, and a `<db>_<new-major>_<new-minor>()` function that starts
   `latest/<db>/docker-compose.yaml` — then point the plain `<db>()` entry point at the new
   latest-version function.
3. Add both new functions to the usage/help list in `db.sh`.

Not every bump needs a versioned copy — use your judgement on whether the previous version
is worth continuing to test (this repo doesn't keep one for every single minor release).

---

### Overview (`hibernate-core/src/jmh/README.md`)

# ActionQueue JMH Benchmarks

This directory contains JMH (Java Microbenchmark Harness) benchmarks for comparing the performance of legacy ActionQueue vs graph-based ActionQueue implementations.

## Benchmark Types

### 1. **ActionQueueBenchmark** (Average Time Mode)
Measures average time per operation in milliseconds. Lower is better.
- Focus: Latency and timing characteristics
- Mode: `AverageTime`
- Unit: `ms/op`

### 2. **ActionQueueThroughputBenchmark** (Throughput Mode)
Measures operations per second. Higher is better.
- Focus: Maximum throughput and operations/second
- Mode: `Throughput`
- Unit: `ops/s`

## Running Benchmarks

### Run all benchmarks
```bash
./gradlew :hibernate-core:jmh
```

### Run specific benchmark class
```bash
# Run only average time benchmarks
./gradlew :hibernate-core:jmh --args="ActionQueueBenchmark"

# Run only throughput benchmarks
./gradlew :hibernate-core:jmh --args="ActionQueueThroughputBenchmark"
```

### Run specific benchmark pattern
```bash
# Run only simple insert benchmarks (both average time and throughput)
./gradlew :hibernate-core:jmh --args="simpleInserts"

# Run only throughput benchmarks for single entity inserts
./gradlew :hibernate-core:jmh --args="singleEntityInsert"

# Run only parent-child benchmarks
./gradlew :hibernate-core:jmh --args="parentChild"

# Run only self-referencing tree benchmarks (average time only)
./gradlew :hibernate-core:jmh --args="selfRefTree"

# Run only mixed operations benchmarks
./gradlew :hibernate-core:jmh --args="mixedOperations"

# Run only OrderColumn benchmarks (throughput only)
./gradlew :hibernate-core:jmh --args="orderColumn"
```

### Run specific benchmark with custom parameters
```bash
# Run with more iterations
./gradlew :hibernate-core:jmh --args="-wi 10 -i 20 simpleInserts"

# Run with more forks for statistical stability
./gradlew :hibernate-core:jmh --args="-f 3 simpleInserts"

# Output results in JSON format
./gradlew :hibernate-core:jmh --args="-rf json -rff results.json"
```

## Benchmark Scenarios

### ActionQueueBenchmark (Average Time)

#### 1. Simple Inserts (`simpleInserts_*`)
- **What**: Bulk insert of entities with no foreign key relationships
- **Why**: Baseline performance comparison without FK dependency overhead
- **Variants**:
  - `simpleInserts_100_*`: 100 entities per transaction
  - `simpleInserts_1000_*`: 1,000 entities per transaction

#### 2. Parent-Child Inserts (`parentChild_*`)
- **What**: Parent entities with cascaded children (one-to-many with FK)
- **Why**: Measures FK dependency handling performance
- **Variants**:
  - `parentChild_10_*`: 10 parents × 10 children = 110 entities
  - `parentChild_100_*`: 100 parents × 10 children = 1,100 entities

#### 3. Self-Referencing Trees (`selfRefTree_*`)
- **What**: Hierarchical tree structures with self-referential FKs
- **Why**: Tests self-referencing FK optimization (grouping strategy)
- **Variants**:
  - `selfRefTree_10_*`: 10 trees × 13 nodes = 130 entities
  - `selfRefTree_50_*`: 50 trees × 13 nodes = 650 entities
- **Structure**: Each tree has 1 root + 3 children + 9 grandchildren

#### 4. Mixed Operations (`mixedOperations_*`)
- **What**: INSERT, UPDATE, DELETE operations in sequence
- **Why**: Tests realistic mixed workload performance
- **Operations**:
  - Insert 50 parents with 5 children each (300 entities)
  - Update all 50 parents
  - Delete all 50 parents and their children

### ActionQueueThroughputBenchmark (Throughput)

#### 1. Single Entity Insert (`singleEntityInsert_*`)
- **What**: Insert one entity per transaction (minimal overhead)
- **Why**: Measures pure transaction throughput with minimal ActionQueue load
- **Metric**: Transactions per second

#### 2. Batch Insert (`batchInsert_50_*`)
- **What**: Insert 50 entities in a single transaction
- **Why**: Measures batch insertion throughput
- **Metric**: Batch operations per second

#### 3. Parent-Child Insert (`parentChildInsert_*`)
- **What**: Insert 1 parent with 10 children (cascade)
- **Why**: Measures throughput with FK dependencies
- **Metric**: Parent-child graph inserts per second

#### 4. Entity Update (`entityUpdate_*`)
- **What**: Complete lifecycle: insert → update → delete
- **Why**: Measures update operation throughput
- **Metric**: Update cycles per second

#### 5. Collection Add (`collectionAdd_*`)
- **What**: Add children to existing parent collection
- **Why**: Measures collection modification throughput
- **Metric**: Collection modification operations per second

#### 6. OrderColumn Insert (`orderColumnInsert_*`)
- **What**: Insert order with 20 line items using @OrderColumn
- **Why**: Measures @OrderColumn update SQL generation performance
- **Metric**: OrderColumn operations per second

#### 7. Mixed Workload (`mixedWorkload_*`)
- **What**: Insert 10 entities, update 5, delete all
- **Why**: Realistic mixed operation throughput
- **Metric**: Mixed workload cycles per second

#### 8. Complex Cascade (`complexCascade_*`)
- **What**: Insert 5 parents with 8 children each (40 entities total)
- **Why**: Measures complex cascade throughput
- **Metric**: Complex cascade operations per second

#### 9. Exceed Batch Size 100 (`exceedBatchSize_100_*`)
- **What**: Insert 100 entities (batch size is 50, requires 2 batches)
- **Why**: Measures performance when operations span multiple JDBC batches
- **Metric**: Operations per second with multi-batch handling

#### 10. Exceed Batch Size 500 (`exceedBatchSize_500_*`)
- **What**: Insert 500 entities (batch size is 50, requires 10 batches)
- **Why**: Measures scalability with large operations requiring many batches
- **Metric**: Large batch operations per second

#### 11. Mixed Exceed Batch (`mixedExceedBatch_*`)
- **What**: Insert 100, update 60, delete 100 (all exceed batch size)
- **Why**: Tests mixed operation types with multi-batch execution
- **Metric**: Mixed multi-batch cycles per second

#### 12. Cascade Exceed Batch (`cascadeExceedBatch_*`)
- **What**: Insert 15 parents with 5 children each (90 entities, exceeds batch size)
- **Why**: Tests cascade operations requiring multiple batches
- **Metric**: Large cascade operations per second

## Understanding Results

### Average Time Mode (ActionQueueBenchmark)
JMH reports average time per operation in milliseconds. **Lower is better.**

Example output:
```
Benchmark                                      Mode  Cnt   Score   Error  Units
ActionQueueBenchmark.simpleInserts_100_Legacy  avgt   10  45.231 ± 2.156  ms/op
ActionQueueBenchmark.simpleInserts_100_Graph   avgt   10  41.087 ± 1.943  ms/op
```

This means:
- Legacy: ~45ms per operation (100 inserts)
- Graph: ~41ms per operation (100 inserts)
- **Graph is ~9% faster** for this scenario
- Calculation: `(45.231 - 41.087) / 45.231 × 100% = 9.2% improvement`

### Throughput Mode (ActionQueueThroughputBenchmark)
JMH reports operations per second. **Higher is better.**

Example output:
```
Benchmark                                             Mode  Cnt     Score     Error  Units
ActionQueueThroughputBenchmark.singleEntityInsert_Legacy  thrpt    5   245.123 ±  12.345  ops/s
ActionQueueThroughputBenchmark.singleEntityInsert_Graph   thrpt    5   278.456 ±  10.234  ops/s
```

This means:
- Legacy: ~245 operations per second
- Graph: ~278 operations per second
- **Graph is ~14% higher throughput** for this scenario
- Calculation: `(278.456 - 245.123) / 245.123 × 100% = 13.6% improvement`

### Which Mode to Use?
- **Average Time**: Best for understanding latency and timing characteristics
- **Throughput**: Best for understanding maximum sustainable load
- Both are valuable for different performance concerns

## Benchmark Configuration

Default settings (configured in `hibernate-core.gradle`):
- **Warmup iterations**: 5 (1 second each)
- **Measurement iterations**: 10 (1 second each)
- **Fork**: 1 JVM fork
- **Mode**: Average time per operation
- **Time unit**: Milliseconds

These can be overridden via command-line args.

## JMH Arguments Reference

Common JMH arguments:
- `-wi <count>`: Warmup iterations (default: 5)
- `-w <time>`: Warmup time per iteration (default: 1s)
- `-i <count>`: Measurement iterations (default: 10)
- `-r <time>`: Measurement time per iteration (default: 1s)
- `-f <count>`: Number of forks (default: 1)
- `-t <count>`: Number of threads
- `-rf <format>`: Result format (text, csv, json, latex)
- `-rff <file>`: Result file name
- `-prof <profiler>`: Enable profiler (gc, stack, etc.)

Example with profiling:
```bash
./gradlew :hibernate-core:jmh --args="-prof gc simpleInserts"
```

## Comparing Results

To compare legacy vs graph implementations:
1. Look for pairs of benchmarks ending in `_Legacy` and `_Graph`
2. Compare the `Score` column:
   - **Average Time**: Lower is better
   - **Throughput**: Higher is better
3. Calculate improvement:
   - **Average Time**: `(Legacy - Graph) / Legacy × 100%` (positive = faster)
   - **Throughput**: `(Graph - Legacy) / Legacy × 100%` (positive = more throughput)

### Quick Comparison Commands
```bash
# Run both implementations side-by-side for single entity inserts
./gradlew :hibernate-core:jmh --args="singleEntityInsert"

# Compare throughput across all scenarios
./gradlew :hibernate-core:jmh --args="ActionQueueThroughputBenchmark -rf json -rff throughput-results.json"

# Compare average time across all scenarios
./gradlew :hibernate-core:jmh --args="ActionQueueBenchmark -rf json -rff avgtime-results.json"
```

## CI/Automated Testing

For CI environments, use fewer iterations for faster results:
```bash
./gradlew :hibernate-core:jmh --args="-wi 2 -i 5 -rf json -rff benchmark-results.json"
```

Then parse the JSON results for regression detection.

---

### Overview (`tooling/hibernate-maven-plugin/src/intTest/resources/5-minute-tutorial/README.md`)

To run this example:
  - Have [Apache Maven](https://maven.apache.org) installed
  - Have [H2 Sakila database](https://github.com/hibernate/sakila-h2) running
  - Issue one of the following commands from a command-line window opened in this folder:
    - `mvn generate-sources -Dh2.version=${h2.version} -Dproject.version=${hibernate.version}`

---

### Overview (`tooling/hibernate-maven-plugin/src/intTest/resources/hbm2java/jpa-default/README.md`)

To run this example:
  - Have [Apache Maven](https://maven.apache.org) installed
  - Have [H2 Sakila database](https://github.com/hibernate/sakila-h2) running
  - Issue the following commands from a command-line window opened in this folder:
    `mvn generate-sources -Dh2.version=${h2.version} -Dhibernate.version=${hibernate.version}`

---

### Overview (`tooling/hibernate-maven-plugin/src/intTest/resources/hbm2java/no-annotations/README.md`)

To run this example:
  - Have [Apache Maven](https://maven.apache.org) installed
  - Have [H2 Sakila database](https://github.com/hibernate/sakila-h2) running
  - Issue the following commands from a command-line window opened in this folder:
    `mvn generate-sources -Dh2.version=${h2.version} -Dhibernate.version=${hibernate.version}`

---

### Overview (`tooling/hibernate-maven-plugin/src/intTest/resources/hbm2java/no-generics/README.md`)

To run this example:
  - Have [Apache Maven](https://maven.apache.org) installed
  - Have [H2 Sakila database](https://github.com/hibernate/sakila-h2) running
  - Issue the following commands from a command-line window opened in this folder:
    `mvn generate-sources -Dh2.version=${h2.version} -Dhibernate.version=${hibernate.version}`

---

### Overview (`tooling/hibernate-maven-plugin/src/intTest/resources/hbm2java/output-directory/README.md`)

To run this example:
  - Have [Apache Maven](https://maven.apache.org) installed
  - Have [H2 Sakila database](https://github.com/hibernate/sakila-h2) running
  - Issue the following command from a command-line window opened in this folder:
```shell
mvn generate-sources 
  -Dh2.version=${h2.version} 
  -Dhibernate.version=${hibernate.version}  
  -Doutput.dir=./generated-classes
```

---

### Overview (`tooling/hibernate-maven-plugin/src/intTest/resources/hbm2java/template-path/README.md`)

To run this example:
  - Have [Apache Maven](https://maven.apache.org) installed
  - Have [H2 Sakila database](https://github.com/hibernate/sakila-h2) running
  - Issue the following command from a command-line window opened in this folder:
```shell
mvn generate-sources 
  -Dh2.version=${h2.version} 
  -Dhibernate.version=${hibernate.version}  
  -Dtemplate.dir=./templates
```

---

### Overview (`tooling/hibernate-maven-plugin/src/intTest/resources/hbm2java/use-generics/README.md`)

To run this example:
  - Have [Apache Maven](https://maven.apache.org) installed
  - Have [H2 Sakila database](https://github.com/hibernate/sakila-h2) running
  - Issue the following commands from a command-line window opened in this folder:
    `mvn generate-sources -Dh2.version=${h2.version} -Dhibernate.version=${hibernate.version}`

---

### Overview (`tooling/hibernate-maven-plugin/src/intTest/resources/hbm2orm/simple-default/README.md`)

To run this example:
- Have [Apache Maven](https://maven.apache.org) installed
- Issue the following commands from a command-line window opened in this folder:
  `mvn org.hibernate.tool:hibernate-tools-maven:${hibernate.version}:hbm2orm`

---

### Overview (`tooling/hibernate-maven-plugin/src/intTest/resources/hbm2orm/with-user-type/README.md`)

To run this example:
- Have [Apache Maven](https://maven.apache.org) installed
- Issue the following commands from a command-line window opened in this folder:
  `mvn compile org.hibernate.tool:hibernate-tools-maven:${hibernate.version}:hbm2orm`

---

### Overview (`hibernate-core/src/jmh/java/org/hibernate/action/queue/README.md`)

# ActionQueue JMH Benchmarks

This directory contains JMH (Java Microbenchmark Harness) benchmarks for Hibernate's ActionQueue implementations.

## Available Benchmarks

### 1. ActionQueueBenchmark.java
Compares Legacy vs Graph-based ActionQueue implementations for:
- Simple entity inserts
- Parent-child relationship inserts
- Self-referencing tree structures
- Mixed operations (insert + update + delete)

### 2. CollectionBundlingBenchmark.java
Compares Legacy, Graph (no bundling), and Graph (with bundling) for collection operations:
- Small collection inserts (10 items)
- Medium collection inserts (50 items)
- Large collection inserts (200 items)
- Multiple collections per entity
- Batch processing with collections
- Very large collections (500 items)
- Mixed operations

## Running Benchmarks

### Run All ActionQueue Benchmarks
```bash
./gradlew :hibernate-core:jmh
```

### Run Specific Benchmark Class
```bash
./gradlew :hibernate-core:jmh -Pjmh.include=".*ActionQueueBenchmark.*"
./gradlew :hibernate-core:jmh -Pjmh.include=".*CollectionBundlingBenchmark.*"
```

### Run Specific Benchmark Method
```bash
./gradlew :hibernate-core:jmh -Pjmh.include=".*collectionInsert_Small.*"
./gradlew :hibernate-core:jmh -Pjmh.include=".*collectionInsert_Medium.*"
./gradlew :hibernate-core:jmh -Pjmh.include=".*collectionInsert_Large.*"
```

### Run with Custom Parameters
```bash
# More iterations for higher confidence
./gradlew :hibernate-core:jmh -Pjmh.include=".*CollectionBundling.*" \
  -Djmh.iterations=20 \
  -Djmh.warmup=10

# Different fork count
./gradlew :hibernate-core:jmh -Pjmh.include=".*CollectionBundling.*" \
  -Djmh.fork=3
```

## Understanding Results

### Benchmark Modes

The benchmarks run in two modes:

1. **Throughput (ops/ms):** Operations per millisecond - **higher is better**
2. **Average Time (ms/op):** Milliseconds per operation - **lower is better**

### Sample Output
```
Benchmark                                                       Mode  Cnt   Score   Error   Units
CollectionBundlingBenchmark.collectionInsert_Small_Legacy      thrpt   10   0.237 ± 0.002  ops/ms
CollectionBundlingBenchmark.collectionInsert_Small_GraphBundling  thrpt   10   0.313 ± 0.004  ops/ms
CollectionBundlingBenchmark.collectionInsert_Small_Legacy       avgt   10   4.267 ± 0.072   ms/op
CollectionBundlingBenchmark.collectionInsert_Small_GraphBundling   avgt   10   3.144 ± 0.058   ms/op
```

Interpretation:
- Graph with bundling: **0.313 ops/ms** (32% faster throughput than legacy)
- Graph with bundling: **3.144 ms/op** (26% faster average time than legacy)

### Error Margins

The `±` value represents the 99.9% confidence interval. Smaller is better, indicating more consistent results.

## Results Location

Benchmark results are saved to:
```
hibernate-core/target/results/jmh/results.txt
```

## Benchmark Configuration

Default JMH settings (from `hibernate-core.gradle`):
```groovy
jmh {
    jmhVersion = '1.37'
    warmupIterations = 5
    iterations = 10
    fork = 1
}
```

### What These Mean

- **warmupIterations:** Number of warmup iterations to let JVM optimize code
- **iterations:** Number of measurement iterations for actual results
- **fork:** Number of separate JVM processes to run benchmarks in

## Tips for Accurate Benchmarking

1. **Close unnecessary applications** to reduce system noise
2. **Run multiple times** and compare results for consistency
3. **Don't run other heavy tasks** during benchmarking
4. **Use profilers** to understand why performance differs:
   ```bash
   ./gradlew :hibernate-core:jmh -Pjmh.include=".*YourBenchmark.*" -Djmh.prof=gc
   ```

5. **Compare similar workloads** (same collection size, same operation type)

## Adding New Benchmarks

### Basic Structure
```java
@State(Scope.Benchmark)
@BenchmarkMode({Mode.AverageTime, Mode.Throughput})
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 10, time = 1)
@Fork(value = 1)
public class MyBenchmark {

    @State(Scope.Benchmark)
    public static class MyState {
        SessionFactory sessionFactory;

        @Setup(Level.Trial)
        public void setup() {
            // Initialize session factory
        }

        @TearDown(Level.Trial)
        public void tearDown() {
            // Cleanup
        }
    }

    @Benchmark
    public void myBenchmark(MyState state, Blackhole blackhole) {
        // Benchmark code
        blackhole.consume(result);
    }
}
```

### State Scopes

- **Scope.Benchmark:** Shared across all threads in benchmark
- **Scope.Thread:** One instance per thread
- **Scope.Group:** One instance per thread group

### Setup/TearDown Levels

- **Level.Trial:** Once per benchmark run
- **Level.Iteration:** Once per iteration
- **Level.Invocation:** Once per invocation (use sparingly, adds overhead)

## Profiling

JMH includes several profilers:

```bash
# GC profiler
./gradlew :hibernate-core:jmh -Pjmh.include=".*MyBench.*" -Djmh.prof=gc

# Stack profiler
./gradlew :hibernate-core:jmh -Pjmh.include=".*MyBench.*" -Djmh.prof=stack

# Class loader profiler
./gradlew :hibernate-core:jmh -Pjmh.include=".*MyBench.*" -Djmh.prof=cl

# List all available profilers
./gradlew :hibernate-core:jmh -Pjmh.include=".*MyBench.*" -Djmh.prof=help
```

## Common Issues

### OutOfMemoryError
Increase heap size:
```bash
export GRADLE_OPTS="-Xmx4g"
./gradlew :hibernate-core:jmh
```

### Inconsistent Results
- Increase warmup iterations
- Run with more forks
- Close background applications

### Slow Benchmarks
- Reduce iterations for quick testing
- Use specific benchmark includes
- Comment out slow benchmarks during development

## References

- [JMH Home](https://github.com/openjdk/jmh)
- [JMH Samples](https://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/)
- [How to Write Good Benchmarks](https://psy-lob-saw.blogspot.com/p/jmh-related-posts.html)

## Result Documentation

- [JMH_BENCHMARK_RESULTS.md](JMH_BENCHMARK_RESULTS.md) - Detailed collection bundling results
- [BENCHMARK_RESULTS.md](../../../test/java/org/hibernate/orm/test/action/queue/bundling/BENCHMARK_RESULTS.md) - Simple benchmark results

---

### Documentation Src Main Asciidoc Dialect Provider Index (`documentation/src/main/asciidoc/dialect-provider/index.adoc`)

include::{root-project-dir}/.asciidoctorconfig.adoc[]
:doctype: book
:icons: font
:html-meta-canonical-link: https://docs.hibernate.org/stable/orm/dialect-provider/
:provider-fixture-dir: {root-project-dir}/tooling/hibernate-dialect-provider/src/providerFixtureTest/java/org/example/orm/dialect
:provider-fixture-main-dir: {root-project-dir}/tooling/hibernate-dialect-provider/src/providerFixture/java/org/example/orm/dialect
:provider-fixture-resources-dir: {root-project-dir}/tooling/hibernate-dialect-provider/src/providerFixture/resources


= Dialect Provider Guide
:toc2:
:toclevels: 3
:sectanchors:

This guide is for authors who publish a SQL Dialect independently of Hibernate
ORM. The link:{doc-dialect-url}[Dialect guide] catalogs available Dialects;
this guide explains how to implement, package, and verify one. Read the
link:{doc-spi-url}[SPI and Service Provider Guide] first for the meaning of
`USE`, `IMPLEMENT`, and `SUPPLY`.

== Provider project setup

Compile against the normal `org.hibernate.orm:hibernate-core` artifact. Do not
depend on `hibernate-testing` or Hibernate's test classes. Keep the provider in
its own artifact and publish an explicit Hibernate compatibility range.

For Gradle builds, apply the provider tooling plugin alongside the Java plugin:

[source,groovy,subs="attributes+"]
----
plugins {
    id("java-library")
    id("org.hibernate.orm.dialect-provider") version "{fullVersion}"
}

dependencies {
    compileOnly("org.hibernate.orm:hibernate-core:{fullVersion}")
}

hibernateDialectProvider {
    providerPackages.add("com.acme.hibernate.dialect")
    contractProfiles.add("com.acme.hibernate.dialect.AcmeDialectContractProfile")
}
----

The plugin resolves the classification metadata for the Hibernate `X.Y`
release family, validates the normal provider jar, creates the
`dialectProviderTest` source set, aligns the exact-version test kit with Core,
and generates the small JUnit bridge for the explicitly named profile. Put
provider-authored tests in `src/dialectProviderTest/java`.

[NOTE]
====
The Gradle plugin is convenience tooling, not part of the Dialect SPI. Maven,
Ant, and other builds should depend directly on the exact-version
`org.hibernate.orm:hibernate-dialect-testkit`, configure JUnit Jupiter, and
write the small `@TestFactory` bridge shown below. Static external-provider
boundary validation is Gradle-only in this release. The test kit never scans
for or discovers profiles.
====

== Dialect construction and selection

Extend `org.hibernate.dialect.Dialect` or a base class explicitly classified
for `IMPLEMENT`. A no-argument constructor should select the provider's minimum
supported database version. A metadata-aware constructor should copy or default
the `DialectResolutionInfo` version before inherited registration begins.

`Dialect#getVersion()` is the immutable version captured during construction.
Keep minimum-version resolution construction-safe: it must not read subclass
fields before the superclass constructor has completed.

Applications may select a Dialect explicitly with `hibernate.dialect`.

[[dialect-provider-selection-and-resolution]]
=== Explicit names and automatic resolution

Prefer automatic resolution when the database and driver metadata reliably
identify the provider's database. Implement `DialectResolver`, return the
provider Dialect for recognized `DialectResolutionInfo`, and return `null` to
let the next resolver try. Register the implementation as a Java service:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleDialectResolver.java[tags=dialect-resolver]
----

.`META-INF/services/org.hibernate.engine.jdbc.dialect.spi.DialectResolver`
[source,text,indent=0]
----
include::{provider-fixture-resources-dir}/META-INF/services/org.hibernate.engine.jdbc.dialect.spi.DialectResolver[]
----

Applications may instead list resolver class names in
`hibernate.dialect_resolvers`. Explicitly configured resolvers run in their
configured order, then service-loaded resolvers run in discovery order, and
Hibernate's standard resolver runs last. The first non-null Dialect wins. An
ordinary resolver exception is logged and resolution continues, while a JDBC
connection exception propagates.

Use `DialectSelector` only when the provider offers an explicit short name for
`hibernate.dialect`. It maps the configured text, unchanged, to a Dialect class
without constructing a Dialect. Return `null` for any unrecognized name so the
next selector and then Hibernate's standard selector may try it:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleDialectSelector.java[tags=dialect-selector]
----

.`META-INF/services/org.hibernate.boot.registry.selector.spi.DialectSelector`
[source,text,indent=0]
----
include::{provider-fixture-resources-dir}/META-INF/services/org.hibernate.boot.registry.selector.spi.DialectSelector[]
----

Choose provider short names which are unlikely to collide. The first matching
service wins, but Java service-provider ordering across independent artifacts
is not a portable conflict-resolution mechanism. The test kit deliberately
does not discover resolvers or selectors; a `DialectContractProfile` creates
the exact Dialect under test.

[WARNING]
====
Implement only the public `DialectResolver` or `DialectSelector` contract.
`org.hibernate.boot.registry.selector.internal.LazyServiceResolver` is an
internal Core adapter with no release-family compatibility guarantee and must
not appear in provider code or signatures.
====

== Strategy-oriented architecture

The link:{doc-javadoc-url}org/hibernate/dialect/Dialect.html[`Dialect`] is the
provider's composition root. It captures the database version and resolved
configuration, and supplies focused collaborators to Hibernate's type, query,
JDBC, and schema subsystems. A strategy describes one coherent database
variation; it is not a smaller name for an arbitrary group of Dialect methods.

=== Dialect as composition root

Prefer contracts under `org.hibernate.dialect.<feature>.spi` to copying
Hibernate implementation code into a provider. Hibernate implementations in a
matching `.internal` package are not provider contracts, even when their Java
visibility permits an import.

Read both sides of a strategy relationship:

* the strategy type states whether providers may use or implement it;
* the Dialect method states how the strategy is supplied;
* reciprocal `@see` links connect the two declarations;
* `IMPLEMENT` does not imply `SUPPLY`, and `SUPPLY` does not imply discovery.

A supplied object should normally be stable for the Dialect's lifetime and
immutable or thread-safe. A shared constant is appropriate for behavior which
does not depend on database version or provider configuration. Use a per-Dialect
instance when the strategy captures resolved state. A Dialect may implement a
strategy directly and return `this` when the strategy contract permits it.

Do not generalize the non-null rule. Some supply points deliberately return
`null` to select Hibernate's standard behavior or to report that a native form
is unavailable. Follow the exact contract of each method.

=== Choosing an extension level

Use the narrowest supported extension which expresses the database behavior:

. Return a named standard constant or immutable profile.
. Construct a profile with its supported builder or factory.
. Compose or implement the focused strategy.
. Override a narrowly classified rendering hook when its contract explicitly
  supports provider implementation.
. Supply a custom SQL AST translator only when the variation changes SQL tree
  structure or rendering control flow in a way the focused strategies cannot
  express.

Do not replace a translator to change a single capability, and do not override
adjacent strategies merely because one consumer happens to use them together.
Independent capability answers allow Hibernate to compose the same database
rules in schema tooling, mutation planning, SQL AST translation, and tests.

=== Family and implementation bases

A concrete selectable Dialect is not automatically a supported superclass.
Extend `Dialect` or a family base whose Javadoc declares `IMPLEMENT`. For
example, a Sybase-derived provider uses `AbstractSybaseDialect`, while
`SybaseDialect` remains the concrete maintained Dialect selected by
applications:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleSybaseDialect.java[tags=sybase-family-base]
----

The family base preserves the maintained implementation and exposes the
audited Dialect override surface. Choose the version constructor when the
provider already knows its database version and the resolution-info constructor
when bootstrap metadata determines it. Do not infer an implementation contract
from package placement or Java visibility alone.

=== Identifier, metadata, and literal strategies

See the link:{doc-javadoc-url}org/hibernate/dialect/identifier/spi/package-summary.html[identifier SPI],
link:{doc-javadoc-url}org/hibernate/dialect/literal/spi/package-summary.html[literal SPI],
and link:{doc-javadoc-url}org/hibernate/dialect/jdbc/spi/package-summary.html[JDBC strategy SPI]
for the complete contracts.

[cols="23,30,25,22",options="header"]
|===
|Concern |Primary contract |Dialect supply point |Provider guidance

|Identifier rendering and limits
|`IdentifierSupport`
|`getIdentifierSupport()`
|Describe quoting and identifier-length rules independently from JDBC metadata.

|Identifier normalization
|`IdentifierHelperBuildRequest`
|`buildIdentifierHelper(...)`
|Refine the supplied builder and use `JdbcMetadata` availability explicitly.

|Keyword behavior
|`KeywordSupport`, `KeywordRegistration`
|`getKeywordSupport()`, `contributeKeywords(...)`
|Use the strategy for keyword policy and the callback for registration lifecycle.

|Literal rendering
|`LiteralSupport`
|`getLiteralSupport()`
|Implement only database-specific literal forms and delegate the remainder.

|Metadata correction
|`JdbcMetadataOverrides`
|`getJdbcMetadataOverrides()`
|Override unreliable driver answers without pretending that metadata was read.

|Parameter limits and markers
|`ParameterLimits`, `ParameterMarkerStrategy`
|`getParameterLimits()`, `getNativeParameterMarkerStrategy()`
|Keep driver-sensitive marker selection consistent with the configured driver.

|String-value semantics
|`StringValueSemantics`
|`getStringValueSemantics()`
|Describe empty-string, trailing-space, and comparison behavior as one profile.

|Result-column aliases
|`ColumnAliasExtractor`
|`getColumnAliasExtractor()`
|Choose name- or label-based extraction according to reliable driver behavior.
|===

[[dialect-provider-delegating-identifier-helper]]
==== Decorating identifier helpers

Prefer configuring the `IdentifierHelperBuilder` carried by
`IdentifierHelperBuildRequest`. It already represents global quoting,
automatic keyword quoting, identifier casing, namespace support, and common
automatic-quoting rules. The inherited `buildIdentifierHelper()` initializes
identifier casing, keywords, and namespace support from the request. Invoke it
before replacing any of those values with authoritative provider settings,
then build the final helper from the same builder. Settings which the inherited
implementation does not initialize may be applied before invoking it.

When builder configuration cannot express one database rule, decorate the
configured result with `DelegatingIdentifierHelper`. Do not implement
`IdentifierHelper` directly. The interface is a `USE + SUPPLY` runtime result,
while the delegating base is the supported `IMPLEMENT` contract and shields a
provider from newly added forwarding operations.

Each forwarding operation is independent. If custom normalization must affect
the three `toIdentifier()` entry points, override those entry points as well as
`normalizeQuoting()`. Call `super` for ordinary forwarding and retain only the
returned helper as the decorator's delegate; do not retain the build request,
builder, or metadata view.

This provider-owned decorator quotes an otherwise legal identifier beginning
with `provider_`:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleIdentifierHelper.java[tags=identifier-helper-decorator]
----

The Dialect applies automatic-quoting settings not initialized by the inherited
implementation and wraps its result:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleDialect.java[tags=identifier-helper-build]
----

==== Composing datetime literals

`LiteralSupport` owns the complete SQL representation of date, time, and
timestamp literals. A provider implementation is therefore responsible for
database-specific introducers, delimiters, casts, and escape syntax. The
link:{doc-javadoc-url}org/hibernate/dialect/literal/spi/StandardDateTimeLiteralRendering.html[`StandardDateTimeLiteralRendering`]
utility supplies just the standard date or time value between those
database-specific elements.

For example, a database which requires its own timestamp introducer but accepts
the standard value representation may compose the two concerns:

[source,java]
----
@Override
public void appendDateTimeLiteral(
        SqlAppender appender,
        TemporalAccessor temporalAccessor,
        TemporalType precision,
        TimeZone jdbcTimeZone) {
    appender.appendSql( "vendor_timestamp '" );
    StandardDateTimeLiteralRendering.appendAsTimestampWithMicros(
            appender,
            temporalAccessor,
            getTemporalValueSemantics().supportsLiteralOffset(),
            jdbcTimeZone,
            ZeroOffsetLiteralStyle.NUMERIC_OFFSET
    );
    appender.appendSql( '\'' );
}
----

Choose the zero-offset spelling explicitly: `UTC_DESIGNATOR` emits `Z`, while
`NUMERIC_OFFSET` emits `+00:00`. Nonzero offsets retain their numeric value.
Use the overload matching the database's fractional-second precision, and use
the local-time variants only when the literal syntax intentionally excludes an
offset. Providers should not import the internal `DateTimeUtils`; the public
utility is the supported composition boundary.

JDBC metadata is authoritative only when it is accessible and trustworthy.
Metadata-free bootstrap must obtain every required fallback from the Dialect.
Keyword contribution is therefore a lifecycle operation, while identifier and
metadata support objects are stable strategies.

[NOTE]
====
The aggregate-column, locking, row-level-security, and temporal-table
extension families are incubating. Their contracts may change within an
`X.Y` release family and are excluded from the corresponding SPI compatibility
guarantee. Check the generated Javadoc for `@Incubating` before depending on a
strategy, request, result, or SQL AST contract.

The central SQL AST and translator contracts, translator factories and requests,
`JdbcParameterFactory`, and `JdbcOperations` builders are no longer incubating.
The specialized `SqlAstTranslator.renderNamedSetReturningFunction()` hook and
`SetReturningFunctionType`, together with the SQM-coupled `QueryTransformer`,
remain incubating. This does not stabilize the separate execution, mapping-model
mutation, or result-processing contracts; their individual lifecycle markers
continue to apply.
====

=== Type and temporal strategies

See the link:{doc-javadoc-url}org/hibernate/dialect/type/spi/package-summary.html[type SPI],
link:{doc-javadoc-url}org/hibernate/dialect/temporaltype/spi/package-summary.html[temporal-type SPI],
link:{doc-javadoc-url}org/hibernate/dialect/temporal/spi/package-summary.html[temporal-table SPI],
link:{doc-javadoc-url}org/hibernate/dialect/array/spi/package-summary.html[array SPI],
and link:{doc-javadoc-url}org/hibernate/dialect/lob/spi/package-summary.html[LOB SPI]
for the complete contracts.

[cols="23,30,25,22",options="header"]
|===
|Concern |Primary contract |Dialect supply point |Provider guidance

|Physical type capacities
|`TypeSizingProfile`
|`getTypeSizingProfile()`
|Report supported capacities and precision defaults; use `UNSUPPORTED` only as documented.

|Runtime size resolution
|`SizeStrategy`
|`getSizeStrategy()`
|Customize mapped-size calculation without changing the physical capability profile.

|Direct Java Time JDBC access
|`DirectJavaTimeJdbcSupport`
|`getDirectJavaTimeJdbcSupport()`
|Report exact Java classes accepted for scalar access and independently inside native JDBC `STRUCT` and `ARRAY` containers.

|Enum declarations and checks
|`EnumSupport`
|`getEnumSupport()`
|Keep enum DDL, casts, declarations, and value checks in one strategy; distinguish textual and ordinal DDL when their relational representations differ.

|Array types and literals
|`ArraySupport`
|`getArraySupport()`
|Describe native array behavior; separate it from aggregate-column support.

|LOB behavior
|`LobSupport`
|`getLobSupport()`
|Coordinate LOB type classification, materialization, binding, and merge behavior.

|Untyped null binding
|`ObjectNullBindingStrategy`
|`getObjectNullBindingStrategy()`
|Choose the complete binding policy instead of independent Boolean answers.

|Nationalized and zoned types
|`NationalizationSupport`, `TimeZoneSupport`
|`getNationalizationSupport()`, `getTimeZoneSupport()`
|Report type-system behavior, not temporal literal syntax.

|Current date and time
|`CurrentTemporalSupport`
|`getCurrentTemporalSupport()`
|Supply current temporal expressions and database-side timestamp retrieval; report whether the timestamp expression uses standard `current_timestamp` syntax.

|Temporal formatting
|`TemporalFormatSupport`
|`getTemporalFormatSupport()`
|Translate format patterns without absorbing arithmetic or value semantics.

|Temporal arithmetic
|`TemporalOperationSupport`
|`getTemporalOperationSupport()`
|Own timestamp add/diff patterns and other operation grammar.

|Temporal values
|`TemporalValueSemantics`
|`getTemporalValueSemantics()`
|Describe precision loss, rounding, and offset preservation.

|System-versioned tables
|`TemporalTableSupport`
|`getTemporalTableSupport()`
|Keep temporal-table DDL and historical-query behavior separate from temporal types.
|===

Physical type sizing, runtime size calculation, and type registration are
different stages. `registerColumnTypes()`, `contributeTypes()`, and
`initializeFunctionRegistry()` remain lifecycle callbacks, not strategy
objects. Resolve version and provider configuration before inherited type
registration so those callbacks and all supplied strategies observe one state.

When textual and ordinal named finite-domain types require different DDL,
override `EnumSupport#getCreateOrdinalTypeCommands()`. Its default delegates to
`getCreateTypeCommands()` and is therefore appropriate only when both mappings
use the same database representation.

If `CurrentTemporalSupport#currentTimestamp()` returns a database-specific
expression instead of the standard `current_timestamp` function, also override
`usesStandardCurrentTimestampFunction()` to return `false`.

==== Direct Java Time JDBC access

`DirectJavaTimeJdbcSupport` describes whether the Dialect and its selected
driver exchange an exact `java.time` class directly through JDBC. Scalar
support covers both `PreparedStatement#setObject()` and typed
`ResultSet#getObject()`, together with the corresponding callable-statement
operations. Report a class as supported only when both directions work.

The inherited `Dialect` profile assumes the scalar support required by JDBC
4.2: `LocalDate`, `LocalTime`, `LocalDateTime`, `OffsetTime`, and
`OffsetDateTime`. Override `getDirectJavaTimeJdbcSupport()` when a supported
driver does not implement part of that contract, or when the driver supports
the additional `ZonedDateTime` or `Instant` classes. Resolve any driver- or
version-sensitive answer during Dialect construction and return one stable,
thread-safe profile.

Use `DirectJavaTimeJdbcSupports.none()`, `jdbc42()`, `all()`, or `of(...)`
instead of depending on an implementation class. The three-set `of(...)`
overload reports scalar, native JDBC `STRUCT`, and native JDBC `ARRAY` support
independently:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleDialect.java[tags=direct-java-time-jdbc-support]
----

None of the scalar-only profiles infer native-container support: `jdbc42()`,
`all()`, and the varargs `of(...)` report no direct `STRUCT` or `ARRAY`
support. Use the three-set overload only when the driver accepts the exact
class while creating and extracting that container kind.

`OffsetTime` and `OffsetDateTime` are a matched pair within each access path.
Both must be present in the scalar, `STRUCT`, or `ARRAY` set to enable either
one for that path; omitting either class disables both. Support for
`OffsetDateTime` also lets Hibernate represent a mapped `ZonedDateTime` as an
`OffsetDateTime` when exact `ZonedDateTime` access is unavailable. Claim exact
`ZonedDateTime` support only when the driver itself exchanges that class.

`Instant` is not enabled merely by
`hibernate.type.java_time_use_direct_jdbc`. It is considered when the
application selects `INSTANT` with
`hibernate.type.preferred_instant_jdbc_type`, and still requires the Dialect
profile to report `Instant` support.

This strategy describes Java values at the JDBC boundary. Keep it separate
from `TimeZoneSupport`, which describes database type behavior, and
`TemporalValueSemantics`, which describes precision adjustment and temporal
literal offset preservation. If direct access is requested but the profile
reports it unsupported, Hibernate falls back to the corresponding physical
representation and logs the known limitation once per Java Time class, with
the offset pair logged together.

=== Implementing and contributing Java/JDBC types

A custom basic mapping normally pairs a
link:{doc-javadoc-url}org/hibernate/type/descriptor/java/JavaType.html[`JavaType`]
with a
link:{doc-javadoc-url}org/hibernate/type/descriptor/jdbc/JdbcType.html[`JdbcType`].
The Java descriptor owns Java-side equality, wrapping, unwrapping, mutability,
and its JDBC recommendation. The JDBC descriptor owns type codes, binding,
extraction, and optional SQL-literal formatting. Keep those responsibilities
separate even when both descriptors are implemented by the same provider.

The principal provider contracts are:

[cols="28,29,43",options="header"]
|===
|Concern |Contract or base |Guidance

|Java value semantics
|`JavaType`, `BasicJavaType`, `AbstractJavaType`, `AbstractClassJavaType`
|Implement a descriptor or extend the narrowest base whose defaults match the value.

|Mutability
|`MutabilityPlan`, `MutableMutabilityPlan`
|Supply the plan from `JavaType#getMutabilityPlan()`; make immutable plans reusable.

|JDBC access
|`JdbcType`, `BasicBinder`, `BasicExtractor`
|Supply a binder and extractor from the descriptor. Conversion belongs outside those operations.

|Parameterized JDBC types
|`JdbcTypeConstructor`
|Resolve a descriptor from the element JDBC type and the supplied mapping context.

|Aggregate and structured values
|`AggregateJdbcType`, `StructuredJdbcType`
|Treat the registered instance as a prototype, supply the mapping-specific descriptor from `resolveAggregateJdbcType(...)`, and use `AggregateJdbcValues` instead of internal struct helpers.

|Bootstrap registration
|`TypeContributor`, `TypeContributions`
|Register descriptors during metadata bootstrap and never retain the lifecycle-scoped contributions object.
|===

For independently reusable types, expose a `TypeContributor` as a Java service
or register it programmatically. A contributor may register both sides of the
pair and any parameterized constructor in one callback:

[source,java]
----
public final class ProviderTypeContributor implements TypeContributor {
    @Override
    public void contribute(
            TypeContributions contributions,
            ServiceRegistry serviceRegistry) {
        contributions.contributeJavaType( ProviderJavaType.INSTANCE );
        contributions.contributeJdbcType( ProviderJdbcType.INSTANCE );
        contributions.contributeJdbcTypeConstructor(
                ProviderJdbcTypeConstructor.INSTANCE
        );
    }
}
----

A Dialect may perform database-specific registration from
`contributeTypes(...)` using the same callbacks. Invoke inherited registration
before adding or replacing descriptors unless the Dialect deliberately owns
the complete inherited type set. Resolve version and driver configuration
before that inherited call.

For PostgreSQL component-format structured values, extend
`org.hibernate.dialect.type.spi.AbstractPostgreSQLStructJdbcType`. Use its
runtime-model constructor for a mapped aggregate; Hibernate resolves the
boot-model attribute ordering without exposing the boot mapping as a provider
dependency. Implement only the driver binding, extraction, and write-expression
variation owned by the provider.

==== Aggregate JDBC values and native containers

`AggregateJdbcType` separates a mapped aggregate from the single native value
bound to or extracted from the JDBC driver. A provider implementing a custom
aggregate or structured type owns the encoding of that native container. For
example, a document-oriented driver might encode an `Object[]` as a native
document and decode that document back into component values.

`AggregateJdbcValues` owns the Hibernate mapping work on either side of that
provider codec. Use `fromDomainValue(...)` before encoding a native value, use
`toLogicalJdbcValues(...)` to implement
`AggregateJdbcType#extractJdbcValues(...)`, and use `toDomainValue(...)` when a
JDBC extractor must return the mapped embeddable value:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleStructuredJdbcType.java[tags=aggregate-jdbc-values]
----

The no-order overloads use Hibernate's logical mapping order. If the native
container has a different physical order, create an immutable
`AggregateJdbcValueOrder` with the logical value found at each physical
position. Thus `physicalOrder(2, 0, 1)` transforms logical values `[A, B, C]`
to physical values `[C, A, B]`. The order is validated as a complete
permutation and its inverse is calculated once.

[IMPORTANT]
====
Decode the provider-specific container before calling `AggregateJdbcValues`,
and normalize driver-specific scalar anomalies as part of that decoding. The
facade handles mapping conversion, nested aggregates, discriminators, and
ordering; it does not understand arbitrary native document formats. Do not use
the internal `StructHelper` or expose `StructAttributeValues` from provider
code.
====

For a provider codec backed by a native JDBC `STRUCT` or `ARRAY`, component
values produced by `AggregateJdbcValues#fromDomainValue(...)` may use direct
Java Time classes selected by the mapping. Consult `supportsInStruct()` or
`supportsInArray()` before passing such a value to the driver. When that
container path does not support the exact class, use the public
`JavaTimeJdbcType` physical-type and conversion helpers to obtain the
representation expected by the corresponding SQL type. These container
capabilities do not apply to textual JSON, XML, or other provider-defined
document encodings.

Focused facilities cover common composition needs without exposing their Core
implementations:

* `DB2JdbcTypes` supplies stable stock descriptors, including the seven Java
  temporal descriptors with DB2's null-safe typed-`getObject` behavior;
* `LobDataExtraction` materializes a binary stream or CLOB using Hibernate's
  standard closing and exception-conversion behavior. It closes the consumed
  stream or reader, but the caller remains responsible for freeing the JDBC
  locator; and
* `EnumRelationalValues` returns enum names or converter-produced relational
  strings in declaration order. Sort the returned fresh array only when the
  database declaration requires it.

Do not import `.internal` descriptor implementations or utilities merely to
obtain stock behavior. An internal class may change between releases without
the `X.Y` SPI compatibility expectations described in the SPI and Service
Provider Guide.

=== Schema and DDL strategies

See the link:{doc-javadoc-url}org/hibernate/dialect/schema/spi/package-summary.html[schema SPI],
link:{doc-javadoc-url}org/hibernate/dialect/constraint/spi/package-summary.html[constraint SPI],
link:{doc-javadoc-url}org/hibernate/dialect/namespace/spi/package-summary.html[namespace SPI],
link:{doc-javadoc-url}org/hibernate/dialect/identity/spi/package-summary.html[identity SPI],
link:{doc-javadoc-url}org/hibernate/dialect/sequence/spi/package-summary.html[sequence SPI],
and link:{doc-javadoc-url}org/hibernate/dialect/temptable/spi/package-summary.html[temporary-table SPI]
for the complete contracts.

[cols="23,30,25,22",options="header"]
|===
|Concern |Primary contract |Dialect supply point |Provider guidance

|Catalog and schema lifecycle
|`NamespaceSupport`
|`getNamespaceSupport()`
|Render create/drop commands without conflating qualification or catalog separators.

|Conditional DDL
|`IfExistsSupport`
|`getIfExistsSupport()`
|Describe placement independently for each supported database object.

|Table alteration and creation
|`AlterTableSupport`, `TableCreationSupport`
|`getAlterTableSupport()`, `getTableCreationSupport()`
|Return focused fragments and plans which exporters compose.

|Column definitions
|`ColumnDefinitionSupport`
|`getColumnDefinitionSupport()`
|Own column declaration ordering, nullability, defaults, and generated clauses.

|Indexes and constraints
|`IndexDdlSupport`, `ConstraintControlSupport`
|`getIndexDdlSupport()`, `getConstraintControlSupport()`
|Keep index grammar separate from runtime enable/disable commands.

|Truncation and schema drop
|`TruncateSupport`, `SchemaDropSupport`
|`getTruncateSupport()`, `getSchemaDropSupport()`
|Preserve command ordering and multi-command results.

|Foreign keys and checks
|`ForeignKeySupport`, `CheckConstraintSupport`
|`getForeignKeySupport()`, `getCheckConstraintSupport()`
|Render focused constraint fragments consumed by schema exporters.

|Database-object comments
|`SchemaCommentSupport`
|`getSchemaCommentSupport()`
|Handle schema-object comments only, not SQL query comments.

|Identity and sequences
|`IdentityColumnSupport`, `SequenceSupport`
|`getIdentityColumnSupport()`, `getSequenceSupport()`
|Keep value generation and DDL/extraction behavior consistent.

|Complete object commands
|`Exporter`, `TableMigrator`, `TableCleaner`
|the `get...Exporter()`, `getTableMigrator()`, and `getTableCleaner()` methods
|Use exporters for complete commands and support strategies for focused pieces.

|Temporary-table lifecycle
|`TemporaryTableStrategy`, `TemporaryTableExporter`
|persistent/local/global strategy methods and `getTemporaryTableExporter()`
|Make the selected strategy kind, lifecycle commands, and exporter agree.
|===

`NameQualifierSupport`, `getCatalogSeparator()`, and `NamespaceSupport` are
related but independent. The first describes which qualifiers are supported,
the second supplies metadata-free catalog punctuation, and the third owns
catalog/schema creation and removal.

=== Query-shape strategies

Query strategies describe independent pieces of database grammar. They remain
Dialect capabilities even when the SQL AST translator is their primary
consumer.

See the link:{doc-javadoc-url}org/hibernate/dialect/sql/ast/spi/package-summary.html[Dialect SQL AST SPI],
link:{doc-javadoc-url}org/hibernate/dialect/function/spi/package-summary.html[function SPI],
link:{doc-javadoc-url}org/hibernate/dialect/aggregate/spi/package-summary.html[aggregate SPI],
and link:{doc-javadoc-url}org/hibernate/dialect/queryhint/spi/package-summary.html[query-hint SPI]
for the complete contracts.

[cols="23,30,25,22",options="header"]
|===
|Concern |Primary contract |Dialect supply point |Provider guidance

|Predicates and row values
|`PredicateSupport`, `RowValueSupport`
|`getPredicateSupport()`, `getRowValueSupport()`
|Describe placement and tuple grammar independently.

|Aggregate and window syntax
|`TupleCountSupport`, `ExpressionCoercionSupport`, `WindowFunctionSupport`
|the corresponding `get...Support()` methods
|Report exact function forms without creating an aggregate catch-all.

|Set operations and subqueries
|`SetOperationSupport`, `SubquerySupport`
|`getSetOperationSupport()`, `getSubquerySupport()`
|Represent each placement restriction explicitly.

|Ordering and grouping
|`NullOrderingSupport`, `FunctionalDependencyAnalysisSupport`
|`getNullOrderingSupport()`, `getFunctionalDependencyAnalysisSupport()`
|Separate null precedence from group-by functional-dependency rules.

|Tableless and synthetic roots
|`SingleRowTableSupport`, `SyntheticTableGroupSupport`
|`getSingleRowTableSupport()`, `getSyntheticTableGroupSupport()`
|Use a synthetic root only for the query shapes which require one.

|Common table expressions
|`CteSupport`
|`getCteSupport()`
|Describe placement, recursion, materialization, and mutation capabilities.

|DML grammar
|`MutationSyntaxSupport`, `DmlTargetColumnQualifierSupport`
|`getMutationSyntaxSupport()`, `getDmlTargetColumnQualifierSupport()`
|Keep mutation syntax separate from bulk-mutation execution planning.

|Values and fetch clauses
|`ValuesListSupport`, `FetchClauseSupport`
|`getValuesListSupport()`, `getFetchClauseSupport()`
|Report context support for `values` independently of list cardinality; an unsupported context is emulated even for one row.

|Query hints
|`QueryHintPlacement`
|`getQueryHintPlacement()`
|Coordinate placement with the retained focused hint-rendering methods.
|===

Prefer a named standard profile for a standard database rule:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleDialect.java[tags=standard-strategy-profile]
----

Use builders and immutable value profiles when several independent features
must be stated together:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleDialect.java[tags=built-query-strategies]
----

`SyntheticTableGroupSupport` is the canonical example of this architecture. A
focused capability replaced database-specific SQM converters which existed
only to add a synthetic table root for literal grouping or ordering.

[[dialect-provider-function-contracts]]
=== Function contribution and descriptor contracts

Function registration is a bootstrap lifecycle, not a long-lived strategy.
A Dialect contributes its database-specific function set from
`initializeFunctionRegistry(FunctionContributions)`. A library or application
which contributes functions independently of a Dialect implements
`FunctionContributor` and supplies it through Java service loading,
`Configuration#registerFunctionContributor()`, or
`MetadataBuilder#applyFunctions()`.

Both callbacks receive a boot-scoped `FunctionContributions`. Use it to obtain
the `SqmFunctionRegistry`, `TypeConfiguration`, and services, complete all
registrations before returning, and retain neither the contribution context nor
the mutable registry. Independent contributors execute in ascending ordinal
order before the Dialect callback. A later registration under the same key
replaces an earlier one.

Choose the smallest supported extension level which expresses the function:

[cols="28,33,39",options="header"]
|===
|Need |Contract |Provider guidance

|A stock Hibernate definition or database variant
|`CommonFunctionFactory`
|Construct it inside the callback, invoke the required stock methods, and
discard it before returning. The factory supports use, not subclassing or
supply.

|A simple provider-defined named or pattern function
|`SqmFunctionRegistry` descriptor builders
|Configure validation, return-type inference, argument-type inference, and
rendering through a builder, then register immediately.

|Custom SQM generation
|`SqmFunctionDescriptor` or `AbstractSqmFunctionDescriptor`
|Implement a reusable descriptor and register its stable instance through a
descriptor-accepting supply point.

|Custom self-rendering SQL
|`FunctionRenderer` or `AbstractSqmSelfRenderingFunctionDescriptor`
|Own SQL AST rendering in the descriptor. Use a supported focused Dialect
function base when its existing behavior is the intended starting point.
|===

For example, a Dialect may combine a stock definition, a simple pattern, and a
provider-owned descriptor in the same callback:

[source,java]
----
@Override
public void initializeFunctionRegistry(FunctionContributions contributions) {
    super.initializeFunctionRegistry( contributions );

    new CommonFunctionFactory( contributions ).cot();
    contributions.getFunctionRegistry()
            .patternDescriptorBuilder( "provider_concat", "(?1 || ?2)" )
            .setExactArgumentCount( 2 )
            .register();
    contributions.getFunctionRegistry().register(
            "provider_self_rendering",
            new ProviderSelfRenderingFunctionDescriptor()
    );
}
----

The selected general, array, and JSON descriptor bases are supported where
their Javadocs declare `IMPLEMENT`; the package as a whole is not an
implementation contract. `CommonFunctionFactory` is a supported catalog of
stock registrations for the current Hibernate `X.Y` release family. Adding a
stock method is compatible, while removing or incompatibly changing an
existing stock method is not. Its instances are callback-local helpers and are
never supplied to Hibernate.

See the link:{doc-javadoc-url}org/hibernate/boot/model/FunctionContributor.html[`FunctionContributor`],
link:{doc-javadoc-url}org/hibernate/query/sqm/function/SqmFunctionDescriptor.html[`SqmFunctionDescriptor`],
link:{doc-javadoc-url}org/hibernate/query/sqm/function/SqmFunctionRegistry.html[`SqmFunctionRegistry`],
and link:{doc-javadoc-url}org/hibernate/dialect/function/CommonFunctionFactory.html[`CommonFunctionFactory`]
contracts for exact roles, constructors, and supply points.

=== Execution, locking, and mutation strategies

See the link:{doc-javadoc-url}org/hibernate/dialect/lock/spi/package-summary.html[locking SPI],
link:{doc-javadoc-url}org/hibernate/dialect/pagination/spi/package-summary.html[pagination SPI],
link:{doc-javadoc-url}org/hibernate/dialect/mutation/spi/package-summary.html[bulk-mutation SPI],
link:{doc-javadoc-url}org/hibernate/dialect/generated/spi/package-summary.html[generated-values SPI],
link:{doc-javadoc-url}org/hibernate/dialect/rowid/spi/package-summary.html[row-id SPI],
and link:{doc-javadoc-url}org/hibernate/dialect/rowsecurity/spi/package-summary.html[row-security SPI]
for the complete contracts.
[cols="23,30,25,22",options="header"]
|===
|Concern |Primary contract |Dialect supply point |Provider guidance

|Pagination
|`LimitHandler`
|`getLimitHandler()`
|Use a standard handler or implement the request/result contract for custom SQL and JDBC instructions.

|Query locking
|`LockingSupport`, `LockingClauseStrategy`
|`getLockingSupport()`, `getLockingClauseStrategy(...)`
|Use the stable profile for capabilities and the per-request strategy for clause selection.

|Transaction concurrency
|`TransactionConcurrency`, `TransactionConcurrencyResolver`
|`LockingSupport#getTransactionConcurrencyResolver()`
|Resolve the factory's read guarantees and operation conflicts from database configuration and available bootstrap facts.

|Entity locking
|`EntityLockingStrategyFactory`
|`getEntityLockingStrategyFactory()`
|Create a strategy for the supplied request without retaining bootstrap state.

|Bulk mutation fallback
|`MultiTableMutationSupport`
|`getMultiTableMutationSupport()`
|Choose CTE or temporary/persistent-table handling separately for operation families.

|Generated values and row locators
|`GeneratedValuesSupport`, `RowIdSupport`
|`getGeneratedValuesSupport()`, `getRowIdSupport()`
|Coordinate SQL expressions, retrieval, JDBC typing, and physical declaration; return `RowIdSupports.none()` when a variant lacks an inherited row locator.

|Row-level security
|`RowLevelSecurity`
|`getRowLevelSecurity()`
|Keep tenant predicates and supporting DDL in one coherent strategy.

|Callable statements and cursors
|`CallableStatementSupport`, `RefCursorSupportFactory`
|`getCallableStatementSupport()`, `getRefCursorSupportFactory()`
|Separate callable syntax from cursor registration/extraction lifecycle.

|Multi-key loading
|`MultiKeyLoadSizingStrategy`
|`getMultiKeyLoadSizingStrategy()`, `getBatchLoadSizingStrategy()`
|Respect parameter limits when choosing batch sizes.
|===

A custom focused implementation may still be a stable singleton:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleDialect.java[tags=custom-locking-strategy]
----

==== Choosing a locking profile

`Dialect#getLockingSupport()` supplies one cohesive, stable profile for the
Dialect lifetime. Its metadata, clause renderer, table-hint renderer,
completed-SQL rewriter, follow-on policy, connection-timeout strategy, and
transaction-concurrency resolver must
describe the same database behavior. The profile and all reusable components
must be immutable or thread-safe; per-query target collection belongs to the
`LockingClauseStrategy` created for that translation.

Choose the narrowest supported approach:

* Use a named `StandardLockingSupports` factory when extending a maintained
  database family. These factories preserve Hibernate's version thresholds and
  coordinated syntax, timeout behavior, and concurrency resolution.
* Use `StandardLockingSupports.simple(...)` when every timeout has one
  classification, or `parameterized(...)` when wait, no-wait, and skip-locked
  differ. These factories return the SPI interface and do not expose the
  Hibernate-owned implementation.
* Implement `LockingSupport` only when the database requires behavior which
  cannot be expressed by those profiles, such as custom table hints, raw-SQL
  placement, or follow-on policy. Keep the implementation provider-owned and
  return stable components.

A follow-on policy reports whether follow-on locking is required; it does not
guarantee that a particular execution plan supplies the actions needed to
perform it. For completed or raw SQL without those actions, `ALLOW` proceeds
without Hibernate-applied pessimistic locking, `FORCE` fails, and `DISALLOW`
fails when either the policy or SQL-rewrite outcome requires follow-on locking.
`IGNORE` likewise proceeds without Hibernate-applied locking when follow-on is
required.

For statement-clause translation, use
`StandardLockingClauseStrategies.none()` when locking is expressed elsewhere.
Use `standard(...)` to combine a provider-owned `LockingClauseRenderer` with
Hibernate's standard root and join target collection. A custom strategy is
appropriate only when target collection itself differs.

A provider-owned connection-timeout strategy should use
`ConnectionLockTimeoutOperations` for query and command execution so it
participates in Hibernate's SQL logging, statement observation, resource
closing, and exception conversion. MySQL-compatible providers may use
`StandardConnectionLockTimeoutStrategies.mysql(waitForeverValue)` when their
only variation is the value representing an effectively unbounded wait.

==== Resolving transaction concurrency

link:{doc-javadoc-url}org/hibernate/dialect/lock/spi/TransactionConcurrency.html[`TransactionConcurrency`]
describes database behavior for the factory's connections. Hibernate uses its
answers when implementing lock modes, including optimistic version checks and
stateless-session locking. JDBC isolation constants alone do not establish these
answers: for example, SQL Server's read-committed behavior also depends on
`READ_COMMITTED_SNAPSHOT`.

Supply a provider-owned
link:{doc-javadoc-url}org/hibernate/dialect/lock/spi/TransactionConcurrencyResolver.html[`TransactionConcurrencyResolver`]
through `LockingSupport#getTransactionConcurrencyResolver()`, or use a
`StandardLockingSupports.simple(...)` or `parameterized(...)` overload accepting
a resolver. Named database-family factories already supply their associated
resolvers. The default resolver is conservative; it does not infer database
guarantees from the availability of locking syntax. The deprecated
`LockingSupport.Metadata#readsWaitForUncommittedWrites()` flag does not supply
the concurrency descriptor.

The resolver is reusable, but its result belongs to the factory's
`JdbcEnvironment` and is available from `JdbcEnvironment#getTransactionConcurrency()`.
Do not store the resolved result on a potentially shared Dialect or locking
profile. Return an immutable descriptor; `TransactionConcurrencies.builder(...)`
is available for constructing one. Connection isolation and relevant database
settings must remain consistent across the factory. This contract describes
that configuration; it does not change connections or coordinate active sessions.

===== Bootstrap and declarations

Resolution runs with the connection already borrowed by bootstrap, or with a
`null` connection when JDBC access is unavailable. Use the supplied metadata,
established database facts, and any declaration to resolve behavior. Leave
missing facts unknown. In particular, a database's default isolation does not
prove which isolation the factory's connections use.

When a connection is supplied and `JdbcMetadataOnBoot` permits access, query it
for settings needed to distinguish configurations. Do not acquire another
connection, retain or close the supplied connection, or change its settings.
Close statements and result sets created by the resolver. A failed supported
probe may leave facts unknown under `ALLOW`; under `REQUIRE`, it must fail
resolution. A fact for which no probe is supported may remain unknown under
either policy.

`hibernate.transaction.concurrency`, defined by
link:{doc-javadoc-url}org/hibernate/cfg/TransactionSettings.html#TRANSACTION_CONCURRENCY[`TransactionSettings.TRANSACTION_CONCURRENCY`],
accepts a named declaration or a `TransactionConcurrency` instance. The setting's
Javadoc lists the standard names and their meanings. Providers may document
additional names. A name supplies otherwise unavailable facts, including when
JDBC access is disabled; it must not override contradictory observations or
established database facts. Reject invalid names, contradictions, and required
probe failures with `TransactionConcurrencyResolutionException` so bootstrap
fallback does not hide them.

A supplied descriptor instance is authoritative: bootstrap uses it unchanged
without invoking the resolver. Direct resolver calls receiving an instance must
also return it unchanged without probing or validation. The caller is responsible
for its accuracy and immutability. Neither form of declaration configures
connection isolation.

===== Operations, guarantees, and rendered SQL

Describe actual database operations using `Operation`, independently of the
Hibernate lock mode which requested them:

* `READ` is an ordinary read under the configured isolation. It may itself
  acquire locks or provide current committed state.
* `CURRENT_READ` is the explicit strategy for reading current committed state,
  resolving conflicting uncommitted writes before succeeding. It may instead
  fail on a conflict, and need not retain a lock after the statement.
* `SHARED_LOCK_READ` and `UPDATE_LOCK_READ` describe the actual row lock acquired.
  Implementing `PESSIMISTIC_READ` with an update lock does not establish support
  for `SHARED_LOCK_READ`.
* `WRITE` modifies or deletes an existing row and has no read guarantees.

`getBlockingDuration(precedingOperation, concurrentOperation)` describes how long
protection established by the first operation can exclude the second operation
in another transaction on the same existing row. Direction matters. This is a
static database rule, not a measurement of active sessions or elapsed wait time.
`UNKNOWN` and `CONDITIONAL` do not prove exclusion. Predicate locks, phantoms,
schema locks, escalation, and incidental internal waits are outside this contract.

Use `ReadGuarantees` to distinguish stable snapshot visibility, current committed
state, prevention of concurrent modification, and a row lock retained until
transaction completion. A stable snapshot or possible serialization failure
does not establish protection against modification. Report only guarantees
which Hibernate may rely on for the resolved configuration.

Keep the explicit `CURRENT_READ` guarantees consistent with
`LockingSupport#renderCurrentReadTableHint(String, TransactionConcurrency)` and
`renderCurrentReadClause(TransactionConcurrency)`. Hibernate first checks whether
ordinary `READ` already provides `isCurrentRead()`. Otherwise, it requires a
supported `CURRENT_READ` with that guarantee before requesting the explicit
strategy. The default renderers use the profile's share-lock hint or clause;
override them when the database needs a different strategy. A cheaper hint which
waits for writes but retains no lock must not advertise transaction-long protection.

Provider tests should cover resolution with and without JDBC, named declarations
and contradictions, authoritative descriptor instances, and optional versus
required probe failures. Test configuration variants affecting concurrency, and
verify the claimed read guarantees and directional conflicts using separate
transactions against the database, including the SQL rendered for explicit reads.

=== Cross-strategy consistency

Focused strategies remain independent, but some combinations must describe one
valid database configuration.

[cols="35,65",options="header"]
|===
|Supplied behavior |Must agree with

|Transaction concurrency descriptor
|The configured isolation and database settings, actual locks acquired, and current-read hints or clauses rendered by the locking profile.

|Multi-table mutation profile
|The selected CTE and local/global/persistent temporary-table capabilities.

|Temporary-table strategy
|The temporary-table exporter and its create, drop, truncate, and lifecycle commands.

|Temporal-table support
|Type sizing and check-constraint support used to build its DDL profile.

|Identifier helper
|Identifier, keyword, and JDBC metadata behavior.

|Native parameter markers
|Resolved driver/version behavior and parameter limits.

|Schema exporters
|The focused schema, constraint, comment, and `IF EXISTS` strategies they compose.

|SQL AST translator
|Every focused capability consulted by the standard translation pipeline.
|===

For example, the fixture's asymmetric bulk-mutation profile selects a local
temporary table for one operation family, so the Dialect supplies the matching
local strategy:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleDialect.java[tags=local-temporary-table-strategy]
----

When a complete built-in vendor profile matches the provider's database, use
`TemporaryTableStrategies.db2Global()`, `hsqlLocal()`, `mysqlLocal()`,
`oracleLocal()`, or `sqlServerLocal()`. These accessors return the public
`TemporaryTableStrategy` contract; do not depend on the concrete class or its
identity. Implement a provider-owned strategy when any naming, DDL, column, or
lifecycle answer differs.

A CTE selection likewise requires the appropriate non-query CTE feature.
Configured global or entity-specific custom mutation strategies retain their
documented precedence over the Dialect fallback profile.

== SQL AST translation and the global HQL/SQM boundary

`Dialect#getSqlAstTranslatorFactory()` is the only general translator factory
supplied by a Dialect. Returning `null` selects
link:{doc-javadoc-url}org/hibernate/dialect/sql/ast/spi/StandardSqlAstTranslatorFactory.html[`StandardSqlAstTranslatorFactory`].
A custom factory should normally extend that standard factory, remain reusable
and thread-safe, retain no translation request, and create a fresh single-use
translator for every request.

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleDialect.java[tags=sql-ast-translator-factory]
----

Override a focused strategy first when the variation is declarative. Supply a
translator subclass only when rendering requires structural behavior or
control flow which the focused strategies cannot express. A custom translator
must still honor every applicable strategy supplied by its Dialect.

For a JDBC driver whose command language is fundamentally different from SQL,
the factory may instead return a direct `SqlAstTranslator` implementation. Use
`AbstractSqlAstWalker` as the structural traversal base and own the command
representation explicitly. This is appropriate, for example, for a document
database exposed through a JDBC driver; the generated command text need only be
understood by that driver.

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleDirectSqlAstTranslator.java[tags=direct-sql-ast-translator]
----

Direct translators should create their executable query descriptions with
link:{doc-javadoc-url}org/hibernate/sql/exec/spi/JdbcOperations.html[`JdbcOperations`].
Its typed `select()` and `queryMutation()` builders return only SPI interfaces
and hide Hibernate's operation implementations. Supply parameter binders in
command-placeholder order, and identify affected relational tables or their
backend-equivalent query spaces so cache invalidation remains correct.

When a translated command renders query-options-backed pagination placeholders,
create them with
link:{doc-javadoc-url}org/hibernate/sql/ast/spi/query/expression/JdbcParameterFactory.html[`JdbcParameterFactory`].
Its query-limit and query-offset factories produce parameters whose binders read
the original `QueryOptions` instead of ordinary `JdbcParameterBindings`. Add each
binder in command-placeholder order and pass the same parameter instance to the
corresponding `JdbcOperations.SelectBuilder` pagination method. The overloads
accepting `TypeConfiguration` resolve Hibernate's persistence-unit-scoped
`Integer` basic type; use the `BasicType<Integer>` overload only when that type
has already been resolved from the current persistence unit. For other
execution-context-backed values, `custom()` creates a parameter expression from
a JDBC mapping and provider-owned binder without exposing Hibernate internals.

[NOTE]
====
`SqlAstTranslationRequest.ModelMutation` is deliberately not accepted by
either `JdbcOperations` builder. It represents mapping-model work originating
from flush, not a query-language mutation. After translating its
`TableMutation`, call `TableMutation#createMutationOperation(command,
parameterBinders)` so the mapping model retains ownership of the concrete
operation, expectation, callable state, and table metadata.
====

Translator subclasses may call
`getVersionSeedMapping(Expression)` to recognize Hibernate's generated version
seed and obtain its public mapping, or
`isParameterInterpretation(Expression)` when behavior must distinguish an SQM
parameter interpretation from an ordinary JDBC parameter. Both methods are
final provider operations, not override points. To append an expression to a
`SelectClause` without constructing an internal selection implementation, call
`addSqlSelection(Expression)`.

=== Provider expressions and full-MERGE translators

For a provider-owned SQL AST expression, extend
link:{doc-javadoc-url}org/hibernate/dialect/sql/ast/spi/AbstractSelfRenderingExpression.html[`AbstractSelfRenderingExpression`]
instead of directly implementing the low-level `SelfRenderingExpression`
protocol. Supply the nullable mapping type once; the base retains it, owns final
visitor dispatch, and leaves one rendering callback to the provider:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleSelfRenderingExpression.java[tags=self-rendering-expression]
----

For databases whose optional-table mutations use a full insert/update/delete
`MERGE`, extend
link:{doc-javadoc-url}org/hibernate/dialect/sql/ast/spi/SqlAstTranslatorWithMerge.html[`SqlAstTranslatorWithMerge`].
Override the smallest protected `renderMerge...` callback which expresses the
grammar difference:

[source,java,indent=0]
----
include::{provider-fixture-main-dir}/ExampleMergeSqlAstTranslator.java[tags=full-merge-translator]
----

`createMergeOperation()` is final because Hibernate owns SQL collection,
parameter ordering, expectation selection, and operation construction. The
full-MERGE base does not imply that the adjacent `SqlAstTranslatorWithUpsert`
is a supported provider base.

`Dialect#getHqlTranslator()` and `Dialect#getSqmTranslatorFactory()` no longer
exist. HQL parsing and general SQM conversion are query-engine-wide concerns,
not Dialect supply points. Framework integrations which intentionally replace
them use the global settings `hibernate.query.hql.translator` and
`hibernate.query.sqm.translator`, exposed downstream by
link:{doc-javadoc-url}org/hibernate/query/spi/QueryEngineOptions.html[`QueryEngineOptions#getCustomHqlTranslator()` and `getCustomSqmTranslatorFactory()`].

There is no service-loaded or Dialect-level fallback for those global
translators. The standalone fixture's `ExampleSqmTranslatorFactory` verifies
the global request-based integration contract; `ExampleDialect` does not
supply it.

== A database-free contract profile

`org.hibernate.orm:hibernate-dialect-testkit` boots a fixed mapping model with
JDBC metadata access disabled. The profile supplies a fresh Dialect, its expected
version, optional safe settings, and applicability decisions for optional
contracts.

[source,java,indent=0]
----
include::{provider-fixture-dir}/ExampleDialectContractProfile.java[tags=profile]
----

Profile names must be stable and nonblank. `createDialect()` must return a new
instance on every call. Settings must not select a different Dialect, request
JDBC metadata, provide a connection, or execute schema commands.

== Running the generic suite

With the Gradle plugin, name each provider-owned profile in
`hibernateDialectProvider.contractProfiles`. The generated bridge constructs
profiles in declared order and calls `DialectTestKit.contractTests(profile)`;
it does not generate the profile itself and is never packaged in the provider
jar. Run the complete provider verification with:

[source,shell]
----
./gradlew verifyDialectProvider
----

The constituent tasks are `validateDialectProviderBoundaries` and
`dialectProviderTest`. Boundary reports are written to
`build/reports/hibernate-dialect-provider/boundary-validation.txt` and
`boundary-validation.json`. Set `attachToCheck = false` only when another
lifecycle task deliberately invokes `verifyDialectProvider`.

An `INTERNAL_TARGET` finding is a warning: it identifies a dependency with no
release-to-release compatibility guarantee, but does not fail validation by
default. A `MISSING_IMPLEMENT_ROLE` finding is an error because the provider is
extending, implementing, or overriding a declaration which Hibernate does not
support as a provider extension point. Set `warningsAsErrors = true` when a
provider wants internal-use warnings to fail its build. Strict mode changes
only the build outcome; reports continue to identify those findings as
`WARNING`.

A provider-owned SPI contract may extend or implement a Hibernate API contract,
or redeclare one of its methods. The validator recognizes provider SPI by an
`spi` package component or a direct `@SPI` annotation. This source-sensitive
allowance lets a provider compose its own supported contract from Hibernate's
stable API; it does not make the Hibernate API an implementation extension
point for ordinary provider classes. Extending, implementing, or overriding a
Hibernate SPI still requires the target contract to declare `IMPLEMENT`.

=== Reviewing internal-use warnings

An internal-use warning is never a compatibility promise. It means the
provider has chosen to depend on an implementation detail which may change in
any release. The preferred response is to migrate to a documented API or SPI
and make the warning disappear.

Hibernate's community Dialects are checked with the same provider-boundary
engine. Their remaining internal-use warnings stay visible in the generated
report and carry the same lack of compatibility guarantees. The published
Gradle plugin intentionally has no allowlist or suppression mechanism.

Common supported migrations include:

* use `org.hibernate.jdbc.spi.JdbcExceptionHelper` to inspect a JDBC exception
  chain instead of importing the former internal utility;
* select complete vendor profiles through
  `TemporaryTableStrategies` instead of importing vendor implementations from
  `org.hibernate.dialect.temptable.internal`; and
* use the focused translator operations described below instead of naming
  internal SQL AST expression or selection implementations.

For Maven, Ant, or intentionally manual test-kit use, expose one
provider-owned JUnit test factory:

[source,java,indent=0]
----
include::{provider-fixture-dir}/ManualDialectContractTestExample.java[tags=contract-suite]
----

The required contracts cover connectionless bootstrap, basic select and DML
translation, identifier and literal rendering, JDBC parameter order, tableless
and synthetic roots, and schema DDL. Optional contracts cover pagination,
locking, temporary tables, and multi-table mutation. A required contract cannot
be skipped. Mark an optional contract inapplicable only with a nonblank reason.

These tests verify internal consistency and provider integration. They do not
certify SQL by executing it against a database. Keep live-database and container
tests in the provider's own test matrix.

== Provider-specific assertions

Use `DialectTestKit.openContext(profile)` for behavior unique to the provider:

[source,java,indent=0]
----
include::{provider-fixture-dir}/ExampleDialectContractTest.java[tags=provider-assertion]
----

The context is thread-confined and must be closed. `translate()` accepts named
parameters, optional pagination, and a whole-query lock mode. Results are
immutable and include every generated statement and JDBC parameter position.
Positional HQL parameters and alias-specific lock modes are intentionally
outside this initial contract.

== Packaging and compatibility workflow

Before publishing a provider release:

. compile against the oldest and newest supported Hibernate versions;
. run the generic contract profile on each version;
. run provider-specific SQL assertions;
. run the provider's live database matrix;
. inspect deprecation, incubation, SPI, and migration reports;
. document the exact Hibernate and database versions supported.

Do not shade Hibernate Core, expose `.internal` types in provider signatures, or
copy Hibernate implementation classes into the provider artifact.

The Gradle validator reads
`https://docs.hibernate.org/orm/X.Y/metadata/classifications.json.gz`, where
`X.Y` is the resolved Core family. It authenticates the gzip bytes with the
adjacent SHA-256 file. Use `classificationMetadataFile` for an unpublished
family or an online-independent build, and populate the Gradle cache online
before using `--offline`. A plugin/Core family mismatch is an error; exact
maintenance versions within one family need not be identical.

== Troubleshooting

Connection requested during profile boot:: Remove metadata-dependent settings
and resolve provider configuration before inherited type registration.
Unknown HQL entity:: Use the fixed `ContractEntity` model in test-kit requests;
provider mappings are not installed in the generic context.
Parameter order mismatch:: Inspect `GeneratedParameter.jdbcPosition()` rather
than counting `?` characters; a Dialect may expand or add internal binders.
Unexpected SQL family:: Identify the supplying Dialect method and test the
focused strategy before replacing a translator.
`INTERNAL_TARGET` warning:: Replace the upstream `.internal` dependency with a documented
API/SPI contract; moving provider code into a package named `internal` does not
change ownership. The warning means the dependency has no compatibility
guarantee across releases.
`MISSING_IMPLEMENT_ROLE` error:: Extend, implement, or override a Hibernate SPI only when it
is classified with `IMPLEMENT`. A provider SPI may compose a Hibernate API,
but an ordinary provider implementation may not treat API visibility as
subclassing or implementation permission.
Offline metadata miss:: Run once online or configure
`classificationMetadataFile` with a locally generated or mirrored family file.
Live database accepts different SQL:: Keep the database result as the final
authority and add a focused provider assertion plus a live integration test.

---

### Documentation Src Main Asciidoc Dialect Index (`documentation/src/main/asciidoc/dialect/index.adoc`)

include::{root-project-dir}/.asciidoctorconfig.adoc[]
:doctype: book
:icons: font
:html-meta-canonical-link: https://docs.hibernate.org/stable/orm/dialect/


= Dialects
:toc2:
:toclevels: 1
:sectanchors:

A dialect is a class that provides information about the specifics of a database and translators for the SQL dialect of the database.

This guide catalogs available Dialects. Authors and maintainers of external
Dialect implementations should use the link:{doc-dialect-provider-url}[Dialect Provider Guide].
The link:{doc-spi-url}[SPI and Service Provider Guide] defines the general
provider-role and compatibility model used by that guide.

== Supported dialects

Hibernate ORM supports a wide range of dialects out of the box.

Usually, Hibernate supports at least the database version that is also still supported by the respective vendor.
In many cases though, Hibernate supports even older versions of the databases,
but the support for these versions is not guaranteed.

Below is a list of supported dialects and the minimum required version of the database.

include::{generated-report-dir}/dialect/dialect-table.adoc[]

[[third-party-dialects]]
== Third-party dialects

Third-parties publish additional dialects for Hibernate ORM, providing their own support for more databases, or extended support beyond what is built in Hibernate ORM.

These dialects are not directly supported by the Hibernate team:

* The Hibernate ORM CI does not run any test against these dialects, the dialect's authors have their own test suite.
* The Hibernate team will not address issues reported against these dialect, but the dialect's authors have their own issue tracker.

[NOTE]
====
Third-party dialects may not be compatible with all versions of Hibernate ORM.

Check the dialect's own documentation to know more about its compatibility constraints.
The https://hibernate.org/orm/releases/#compatibility-matrix[compatibility matrix on the Hibernate website] may also be of help.
====

Below is a list of third-party dialects with links to relevant websites.

[cols="a,a", options="header"]
|===
|Dialect |Website
|MongoDB| https://github.com/mongodb/mongo-hibernate/[MongoDB extension for Hibernate ORM]
|Google Spanner| https://github.com/GoogleCloudPlatform/google-cloud-spanner-hibernate[Google Cloud Spanner Dialect for Hibernate ORM]
|===

[[community-dialects]]
== Community dialects

Community dialects are not included in `org.hibernate.orm:hibernate-core` and require an additional dependency to `org.hibernate.orm:hibernate-community-dialects`.

These dialects are not directly supported by the Hibernate team:

* The Hibernate ORM CI does not run any test against these dialects.
* The Hibernate team will not address issues reported against these dialect.

Instead, the dialects are maintained on a best-effort basis by vendors or individuals.

Below is a list of community dialects and the minimum required version of the database.

include::{generated-report-dir}/dialect/dialect-table-community.adoc[]

[NOTE]
====
Community dialects were introduced in Hibernate ORM 6.0.

The `hibernate-core` artifact had many legacy dialects before 6.0 that were only tested and maintained on a best effort basis.
More and more database vendors requested to integrate a dialect for their database and even provided a PR with a dialect,
but the Hibernate team didn't want to add new dialects for databases that might not have a wide adoption
or any automated testing into the `hibernate-core` artifact. Even though the dialect was supposedly maintained by the vendor,
the Hibernate team was burdened with reviewing questions, issues and PRs that relate to these dialects.

To give database vendors and the community a clear way forward, the Hibernate team decided to introduce a new artifact,
called `hibernate-community-dialects` which is the new home for dialects that are maintained by vendors or individuals.

Moving forward, the `hibernate-core` artifact will only contain dialects that are supported and tested by the Hibernate team.
All the legacy dialects were moved to the `hibernate-community-dialects` artifact to have a clear separation based on the quality of the dialect.
====

== Requirements for moving from `hibernate-community-dialects` to `hibernate-core`

If a database vendor wants their database dialect to be included in the `hibernate-core` artifact,
several requirements have to be fulfilled:

* The vendor must provide access to a dedicated database server that can be used for testing
* The vendor must provide contact details to at least one employee who is mainly responsible for the maintenance of the dialect
* The responsible employee of the vendor must actively monitor and react to failures of the testsuite against the respective database
* The responsible employee of the vendor must ensure the testsuite is configured correctly in order for it to succeed on the respective database
* If the responsible employee of the vendor leaves the company, the vendor must provide contact details to a new responsible employee

In case the responsible employee is unreachable for a longer period or issues with the dialect are not attended to in a timely manner,
the Hibernate team will move the dialect back to the `hibernate-community-dialects` artifact.

The requirements for the database server are:

* JDK 17 installed
* Git installed
* Access to the database through non-confidential credentials
* Access via SSH through confidential credentials

Get in touch with the Hibernate team on https://hibernate.zulipchat.com/#narrow/stream/132096-hibernate-user[Zulip]
if you want to request the move of your dialect to hibernate-core.

---

### Documentation Src Main Asciidoc Integrationguide Credits (`documentation/src/main/asciidoc/integrationguide/credits.adoc`)

[[credits]]
== Credits

The full list of contributors to Hibernate ORM can be found on the
https://github.com/hibernate/hibernate-orm/graphs/contributors[GitHub repository].

The following contributors were involved in this documentation:

* Steve Ebersole
* Vlad Mihalcea

---

### Documentation Src Main Asciidoc Integrationguide Index (`documentation/src/main/asciidoc/integrationguide/index.adoc`)

= Hibernate ORM Integration Guide
:toc2:
:toclevels: 3
:sectanchors:
:html-meta-canonical-link: https://docs.hibernate.org/stable/orm/integrationguide/html_single/

include::preface.adoc[]

:numbered:

include::chapters/services/Services.adoc[]

include::credits.adoc[]

---

### Documentation Src Main Asciidoc Integrationguide Preface (`documentation/src/main/asciidoc/integrationguide/preface.adoc`)

[[preface]]
== Preface

Hibernate provides many integration points that allow integrating with new capabilities or supplying custom behavior for standard capabilities.  This guide covers these integration points and is intended for software developers and architects who will be

- integrating Hibernate with Java EE application servers, Spring framework, caching solutions (e.g. Infinispan, Ehcache, Hazelcast),
- supplying custom integrations, or
- want to override standard capabilities

---

### Documentation Src Main Asciidoc Introduction Advanced (`documentation/src/main/asciidoc/introduction/Advanced.adoc`)

[[advanced]]
== Advanced Topics

In the last chapter of this Introduction, we turn to some topics that don't really belong in an introduction.
Here we consider some problems, and solutions, that you're probably not going to run into immediately if you're new to Hibernate.
But we do want you to know _about_ them, so that when the time comes, you'll know what tool to reach for.

[[filters]]
=== Filters

_Filters_ are one of the nicest and under-usedest features of Hibernate, and we're quite proud of them.
A filter is a named, globally-defined, parameterized restriction on the data that is visible in a given session.

Examples of well-defined filters might include:

- a filter that restricts the data visible to a given user according to row-level permissions,
- a filter which hides data which has been soft-deleted,
- in a versioned database, a filter that displays versions which were current at a given instant in the past, or
- a filter that restricts to data associated with a certain geographical region.

A filter must be declared somewhere.
A package descriptor or a module descriptor is as good a place as any for a link:{doc-javadoc-url}org/hibernate/annotations/FilterDef.html[`@FilterDef`]:

[source,java]
----
@FilterDef(name = "ByRegion",
           parameters = @ParamDef(name = "region", type = String.class))
package org.hibernate.example;
----

This filter has one parameter.
Fancier filters might in principle have multiple parameters, though we admit this must be quite rare.

[IMPORTANT]
====
In container environments with <<entity-discovery,scanning>>, annotated packages/modules are auto-discovered.

In other environments, to let Hibernate know about the annotated packages/modules:

* If you're using `Configuration` to configure Hibernate, use `Configuration.addPackage()`/`Configuration.addModule()`.
* If you're using `MetadataSources` directly, use `MetadataSources.addPackage()`/`MetadataSources.addModule()`.
====

_Typically_, but not necessarily, a `@FilterDef` specifies a default restriction:

[source,java]
----
@FilterDef(name = "ByRegion",
           parameters = @ParamDef(name = "region", type = String.class),
           defaultCondition = "region = :region")
package org.hibernate.example;
----

Note that filter restrictions are always written in the native SQL dialect of the database, _not_ in HQL.

The restriction must contain a reference to the parameter of the filter, specified using the usual syntax for named parameters.

Any entity or collection which is affected by a filter must be annotated link:{doc-javadoc-url}org/hibernate/annotations/Filter.html[`@Filter`]:

[source,java]
----
@Entity
@Filter(name = example_.BY_REGION)
class User {

    @Id String username;

    String region;

    ...
}
----

Here, as usual, `example_.BY_REGION` is generated by Hibernate Processor, and is just a constant with the value `"ByRegion"`.

If the `@Filter` annotation does not explicitly specify a restriction, the default restriction given by the `@FilterDef` is applied to the entity.
But an entity is free to override the default condition.

[source,java]
----
@Entity
@Filter(name = example_.FILTER_BY_REGION, condition = "name = :region")
class Region {

    @Id String name;

    ...
}
----

Note that the restriction specified by the `condition` or `defaultCondition` is a native SQL expression.

.Annotations for defining filters
[%breakable,cols="25,~"]
|===
| Annotation | Purpose

| `@FilterDef` | Defines a filter and declares its name (exactly one per filter)
| `@Filter` | Specifies how a filter applies to a given entity or collection (many per filter)
|===

[TIP]
====
A filter `condition` may not specify joins to other tables, but it may contain a subquery.
[source,java]
----
@Filter(name="notDeleted"
        condition="(select r.deletionTimestamp from Record r where r.id = record_id) is not null")
----
Only unqualified column names like `record_id` in this example are interpreted as belonging to the table of the filtered entity.
====

By default, a new session comes with every filter disabled.
A filter must be explicitly enabled when the session is created, and arguments must be assigned to its parameters.
One way to do this is using a session creation option:

[source,java]
----
import org.hibernate.SessionCreationOption.EnabledFilter;
...
var enabledFilter =
        new EnabledFilter(example_.FILTER_BY_REGION,
						  // argument to the filter parameter
                          Map.of("region", "es"));
try (var session = factory.createEntityManager(enabledFilter)) {
    var document =
            // read the version of the document
            // effective at the specified instant
            session.find(Document.class, documentId);
    ...
}
----

// A filter may be explicitly enabled in a given session by calling link:{doc-javadoc-url}org/hibernate/Session.html#enableFilter(java.lang.String)[`enableFilter()`] and assigning arguments to the parameters of the filter using the returned instance of link:{doc-javadoc-url}org/hibernate/Filter.html[`Filter`].
// You should do this right at the _start_ of the session.
//
// [source,java]
// ----
// sessionFactory.inTransaction(session -> {
//     session.enableFilter(example_.FILTER_BY_REGION)
//         .setParameter("region", "es")
//         .validate();
//
//     ...
// });
// ----

Now, any queries executed within the session will have the filter restriction applied.
Collections annotated `@Filter` will also have their members correctly filtered.

[NOTE]
====
On the other hand, by default, filters are not applied to `@ManyToOne` associations, nor to `find()`.
This is completely by design and is not in any way a mistake.
The default behavior may be overridden using `@FilterDef(applyToLoadByKey=true)`.
====

More than one filter may be enabled in a given session.

Alternatively, since Hibernate 6.5, a filter may be declared as `autoEnabled` in every session.
In this case, the argument to a filter parameter must be obtained from a `Supplier`.

[source,java]
----
@FilterDef(name = "ByRegion",
           autoEnabled = true,
           parameters = @ParamDef(name = "region", type = String.class,
                                  resolver = RegionSupplier.class),
           defaultCondition = "region = :region")
package org.hibernate.example;
----

It's not necessary to call `enableFilter()` for a filter declared `autoEnabled = true`.

[TIP]
====
When we only need to filter rows by a static condition with no parameters, we don't need a filter, since link:{doc-javadoc-url}org/hibernate/annotations/SQLRestriction.html[`@SQLRestriction`] provides a much simpler way to do that.
====

:envers: https://hibernate.org/orm/envers/
:envers-doc: {doc-user-guide-url}#envers

We've mentioned that a filter can be used to implement versioning, and to provide _historical_ views of the data.
But Hibernate 7.4 introduces two much more powerful ways of dealing with historical data.

[[temporal-data]]
=== Temporal data

A _temporal entity_ is an entity that keeps a history of its state over time, allowing the database to be queried for state which was effective at a given moment in the past.
The link:{doc-javadoc-url}org/hibernate/annotations/Temporal.html[`@Temporal`] annotation declares a temporal entity.

[source,java]
----
@Temporal @Entity
class Document {
	...
}
----

Any temporal entity has columns holding:

- the moment at which a particular version of the entity became effective, and
- the moment, if any, at which it the version is superseded (this is null for the currently-effective version).

[source,java]
----
@Temporal(rowStart="effective",
          rowEnd="superseded")
@Entity
class Document {
	...
}
----

Hibernate offers several different strategies for mapping temporal entities,
enumerated by link:{doc-javadoc-url}org/hibernate/temporal/TemporalTableStrategy.html[`TemporalTableStrategy`].

.Temporal table strategies
[%breakable,cols="15,25,~"]
|===
| Strategy | Explanation | Comments

| `NATIVE` | Use ANSI SQL 2011-style temporal tables
| Requires native database support for temporal tables (Maria, SQL Server, Db2)
| `SINGLE_TABLE` | Store historical data together with current data in one table
| The table does not have the usual foreign key constraints that would exist for any non-temporal entity, and so it is the responsibility of the application program to maintain and enforce referential integrity
| `HISTORY_TABLE` | Maintain two tables, one for current data and one for historical data
| The table for current data has all the usual foreign key constraints that would exist for any non-temporal entity; the table for historical data has no foreign key constraints
|===

The temporal table strategy is controlled by the following property setting:

.Temporal data configuration
[%breakable,cols="36,~"]
|===
| Configuration property name           | Purpose

| link:{doc-javadoc-url}org/hibernate/cfg/StateManagementSettings.html#TEMPORAL_TABLE_STRATEGY[`hibernate.temporal.table_strategy`]  | Specifies the `TemporalTableStrategy`
|===

In the `SINGLE_TABLE` strategy, the `@HistoryPartitioning` annotation allows historical data to be shifted to a separate partition.

[source,java]
----
@Temporal @Entity
@Table(name="documents")
@Temporal.HistoryPartitioning(
        currentPartition="doc_current",
        historyPartition="doc_history")
class Document {
	...
}
----

In the `HISTORY_TABLE` strategy, the `@HistoryTable` annotation specifies the name of the table holding the historical data.

[source,java]
----
@Temporal @Entity
@Table(name="documents")
@Temporal.HistoryTable(name="document_history")
class Document {
	...
}
----

By default, a session or stateless session reads the currently effective version of any temporal entity.
To read historical versions effective at a given instant, we must specify the instant when creating the session or stateless session.

[source,java]
----
import org.hibernate.SessionCreationOption.EffectiveAt;
...
Instant instant = ... ; // a past instant
try (var session = factory.createEntityManager(new EffectiveAt(instant))) {
    var document =
            // read the version of the document
            // effective at the specified instant
            session.find(Document.class, documentId);
    ...
}
----

A temporal entity tracks its state as it changes over time, but it doesn't keep any record of the _changes themselves_, nor about how modifications to the temporal entity relate to other modifications as part of a _changeset_ involving multiple entities.
For this we need an audit log.

[[audit-logs]]
=== Audit logs

An _audited entity_ is quite similar to a temporal entity with a separate history table.
But whereas a history table only tracks the timestamp at which a version became effective, an _audit log_ keeps a record of each changeset and something about the nature of the change.
The link:{doc-javadoc-url}org/hibernate/annotations/Audited.html[`@Audited`] annotation declares an audited entity.

[source,java]
----
@Audited @Entity
class Document {
	...
}
----

The `@Audited.Table` annotation specified the table holding the audit log for that entity:

[source,java]
----
@Audited @Entity
@Table(name="documents")
@Audited.Table(name="document_aud_log")
class Document {
	...
}
----

An audit log is organized around changeset identifiers instead of timestamps.
Each audit log table has columns holding:

- an id of the changeset at which a revision of the entity became effective,
- the nature of the change to entity that resulted in the revision being created--that is, the `ModificationType`,
and
- optionally, an id of the changeset which resulted in the revision being superseded.

[source,java]
----
@Audited @Entity
@Table(name="documents")
@Audited.Table(
        name="document_aud_log",
        changesetIdColumn="REV",
        modificationTypeColumn="REVTYPE")
class Document {
	...
}
----

NOTE: In the past, audit logging was provided by {envers}[Envers].
The functionality underlying the `@Audited` annotation is completely new, but is backward compatible with the format of Envers audit logs.

To make use of audited entities, we need a source of changeset ids.
There are two approaches we could take:

1. create an entity class which holds information about each changeset, and annotate it link:{doc-javadoc-url}org/hibernate/annotations/Changelog.html[`@Changelog`] or,
2. supply our own custom implementation of link:{doc-javadoc-url}org/hibernate/temporal/spi/ChangesetIdentifierSupplier.html[`ChangesetIdentifierSupplier`] to assign changeset ids to transactions.

With the first (recommended) approach, Hibernate automatically persists a new instance of the `@Changelog` entity in each transaction, using the `@ChangesetId` field--typically the generated identifier of the entity--as the changeset id.

[source,java]
----
@Changelog @Entity
@Table(name = "REVINFO")
static class ChangesetInfo {
    @Id
    @GeneratedValue
    @Changelog.ChangesetId
    @Column(name = "REV")
    int id;

    @Changelog.Timestamp
    @Column(name = "REVTSTMP")
    long timestamp;

    @Basic(optional=false)
    String description;
}
----

Notice that the changelog entity is much more than a source of ids.
It also stores information about each changeset, including the moment at which the change occurred.
For those familiar with Envers, the changelog entity fills the role of the Envers "revision entity".
A typical custom changelog entity helps answer questions like "who?", "why?", and "when?".

.Audit log configuration
[%breakable,cols="36,~"]
|===
| Configuration property name           | Purpose

| link:{doc-javadoc-url}org/hibernate/cfg/StateManagementSettings.html#CHANGESET_ID_SUPPLIER[`hibernate.temporal.changeset_id_supplier`] | Specify a custom `ChangesetIdentifierSupplier`
| link:{doc-javadoc-url}org/hibernate/cfg/StateManagementSettings.html#AUDIT_STRATEGY[`hibernate.audit.strategy`]  | Specifies whether there is a column holding the id of the changeset which superseded a revision
|===

By default, a session or stateless session reads the currently effective version of an audited entity and ignores the audit log.
To read historical reversions, we must specify a changeset id when creating the session or stateless session.

[source,java]
----
import org.hibernate.SessionCreationOption.EffectiveChangeset;
...
Long changesetId = ... ; // a changeset id
try (var session = factory.createEntityManager(new EffectiveChangeset(changesetId))) {
    var document =
            // read the reversion of the document
            // effective after the specified changeset
            session.find(Document.class, documentId);
}
----

The link:{doc-javadoc-url}org/hibernate/audit/AuditLog.html[`AuditLog`] interface lets us run more sophisticated queries against the audit log:

[source,java]
----
try (var auditLog = AuditLogFactory.create(factory)) {
    for (var changesetId : auditLog.getChangesets(Document.class, documentId)) {
        // iterate over the changesets which modified the given document
        try (var session = factory.createEntityManager(new EffectiveChangeset(changesetId))) {
             ...
        }
    }
}
----

For even more control, we can open a session with `ALL_CHANGESETS` and write custom HQL queries using the `changesetId()` and `modificationType()` functions:

[source,java]
----
try (var session = factory.createEntityManager(new EffectiveChangeset(AuditLog.ALL_CHANGESETS))) {
    // find all documents deleted in a specific changeset
    var deleted = session.createQuery(
            "from Document d"
                + " where changesetId(d) = :csId"
                + " and modificationType(d) = :type",
            Document.class)
        .setParameter("csId", targetChangesetId)
        .setParameter("type", ModificationType.DEL)
        .getResultList();

    // count modifications per changeset
    var counts = session.createQuery(
            "select changesetId(d), count(d)"
                + " from Document d"
                + " group by changesetId(d)"
                + " order by changesetId(d)",
            Object[].class)
        .getResultList();
}
----

You'll find much more information about these new APIs in the Javadoc.

// [[envers]]
// .Using Envers for auditing historical data
// ****
// Envers is an add-on to Hibernate ORM which keeps a historical record of each versioned entity in a separate _audit table_, and allows past revisions of the data to be viewed and queried.
// A full introduction to Envers would require a whole chapter, so we'll just give you a quick taste here.
//
// First, we must mark an entity as versioned, using the `@Audited` annotation:
// [source,java]
// ----
// @Audited @Entity
// @Table(name="CurrentDocument")
// @AuditTable("DocumentRevision")
// class Document { ... }
// ----
// [TIP]
// ====
// The `@AuditTable` annotation is optional, and it's better to set either `org.hibernate.envers.audit_table_prefix` or `org.hibernate.envers.audit_table_suffix` and let the audit table name be inferred.
// ====
// The `AuditReader` interface exposes operations for retrieving and querying historical revisions.
// It's really easy to get hold of one of these:
// [source,java]
// ----
// AuditReader reader = AuditReaderFactory.get(entityManager);
// ----
// Envers tracks revisions of the data via a global _revision number_.
// We may easily find the revision number which was current at a given instant:
// [source,java]
// ----
// Number revision = reader.getRevisionNumberForDate(datetime);
// ----
// We can use the revision number to ask for the version of our entity associated with the given revision number:
// [source,java]
// ----
// Document doc = reader.find(Document.class, id, revision);
// ----
// Alternatively, we can directly ask for the version which was current at a given instant:
// [source,java]
// ----
// Document doc = reader.find(Document.class, id, datetime);
// ----
// We can even execute queries to obtain lists of entities current at the given revision number:
// [source,java]
// ----
// List documents =
//         reader.createQuery()
//             .forEntitiesAtRevision(Document.class, revision)
//             .getResultList();
// ----
// For much more information, see the {envers-doc}[User Guide].
// ****
//
// Historically, filters where often used to implement soft-delete.
// But, since 6.4, Hibernate now comes with soft-delete built in.

Sometimes, keeping a full record of past revisions of an entity is too much.

[[soft-delete]]
=== Soft-delete

:soft-delete-doc: {doc-user-guide-url}#soft-delete

Even when we don't need complete historical versioning, we often prefer to "delete" a row by marking it as obsolete using a SQL `update`, rather than by executing an actual SQL `delete` and removing the row from the database completely.

The link:{doc-javadoc-url}org/hibernate/annotations/SoftDelete.html[`@SoftDelete`] annotation controls how this works:
[source,java]
----
@Entity
@SoftDelete(columnName = "deleted",
            converter = TrueFalseConverter.class)
class Draft {

    ...
}
----
The `columnName` specifies a column holding the deletion status, and the `converter` is responsible for converting a Java `Boolean` to the type of that column.
In this example, link:{doc-javadoc-url}org/hibernate/type/TrueFalseConverter.html[`TrueFalseConverter`] sets the column to the character `'F'` initially, and to `'T'` when the row is deleted.
Any JPA `AttributeConverter` for the Java `Boolean` type may be used here.
Built-in options include link:{doc-javadoc-url}org/hibernate/type/NumericBooleanConverter.html[`NumericBooleanConverter`] and link:{doc-javadoc-url}org/hibernate/type/YesNoConverter.html[`YesNoConverter`].

Much more information about soft delete is available in the {soft-delete-doc}[User Guide].

Another feature that you _could_ use filters for, but now don't need to, is multi-tenancy.

[[multitenancy]]
=== Multi-tenancy

:multitenacy-doc: {doc-user-guide-url}#multitenacy

A _multi-tenant_ database is one where the data is segregated by _tenant_.
We don't need to actually define what a "tenant" really represents here; all we care about at this level of abstraction is that each tenant may be distinguished by a unique identifier.
And that there's a well-defined _current tenant_ in each session.

We may specify the current tenant when we open a session:

// [source,java]
// ----
// var session =
//         sessionFactory.withOptions()
//             .tenantIdentifier(tenantId)
//             .openSession();
// ----
//
// Or, when using JPA-standard APIs:

[source,java]
----
import org.hibernate.SessionCreationOption.TenantId;
...
try (var entityManager = factory.createEntityManager(new TenantId(tenantId))) {
	...
}
----

However, since we often don't have this level of control over creation of the session, it's more common to supply an implementation of link:{doc-javadoc-url}org/hibernate/context/spi/CurrentTenantIdentifierResolver.html[`CurrentTenantIdentifierResolver`] to Hibernate.

To make use of multi-tenancy, we'll usually need to set at least one of these configuration properties:

.Multi-tenancy configuration
[%breakable,cols="36,~"]
|===
| Configuration property name           | Purpose

| link:{doc-javadoc-url}org/hibernate/cfg/MultiTenancySettings.html#MULTI_TENANT_IDENTIFIER_RESOLVER[`hibernate.tenant_identifier_resolver`]  | Specifies the `CurrentTenantIdentifierResolver`
| link:{doc-javadoc-url}org/hibernate/cfg/MultiTenancySettings.html#MULTI_TENANT_SCHEMA_MAPPER[`hibernate.multi_tenant.schema_mapper`]  | Specifies the `TenantSchemaMapper` for schema-based multi-tenancy
| link:{doc-javadoc-url}org/hibernate/cfg/MultiTenancySettings.html#MULTI_TENANT_CREDENTIALS_MAPPER[`hibernate.multi_tenant.credentials_mapper`]  | Specifies the `TenantCredentialsMapper` for schema-based or discriminator-based multi-tenancy
| link:{doc-javadoc-url}org/hibernate/cfg/MultiTenancySettings.html#MULTI_TENANT_CONNECTION_PROVIDER[`hibernate.multi_tenant_connection_provider`]  | Specifies the `MultiTenantConnectionProvider` for database-based multi-tenancy
| link:{doc-javadoc-url}org/hibernate/cfg/MultiTenancySettings.html#MULTI_TENANT_RLS_ENABLED[`hibernate.multi_tenant.rls_enabled`]  | When `false`, disables enforcement of discriminator-based multi-tenancy via database-native row-level security
|===

// Do not configure those properties if you would like the configured `BeanContainer` provide the implementation.

There are three common approaches to multi-tenancy:

1. each tenant has its own database,
2. each tenant has its own schema, or
3. tenants share tables in a single schema, and rows are tagged with the tenant id.

[discrete]
==== Database-based multi-tenancy

The first option is to give each tenant its own database.
That is, we'll use a separate source of JDBC connections for each tenant.

The interface link:{doc-javadoc-url}org/hibernate/engine/jdbc/connections/spi/MultiTenantConnectionProvider.html[`MultiTenantConnectionProvider`] is responsible for obtaining an appropriate `Connection` for a given tenant.
Typically, we'll provide a custom implementation of this interface:

- from time to time, Hibernate will ask for a connection, passing the id of the current tenant, and then we must create an appropriate connection or obtain one from a pool, and return it to Hibernate, and
- later, Hibernate will release the connection and ask us to destroy it or return it to the appropriate pool.

[TIP]
====
Check out link:{doc-javadoc-url}org/hibernate/engine/jdbc/connections/spi/DataSourceBasedMultiTenantConnectionProviderImpl.html[`DataSourceBasedMultiTenantConnectionProviderImpl`] for inspiration.
If your source of JDBC connections is a set of JNDI-bound ``DataSource``s, you might even be able to use this implementation directly.
====

[discrete]
==== Schema-based multi-tenancy

The second option is to keep all the data for different tenants in the same database, giving each tenant a different named database schema with its own set of tables.

- If all tenants connect to the database using the same credentials, we must supply a link:{doc-javadoc-url}org/hibernate/context/spi/TenantSchemaMapper.html[`TenantSchemaMapper`] which is responsible for mapping tenant ids to schema names.

- If each tenant should use distinct credentials to connect to the database, and if your JDBC `DataSource` supports this (not all do!) then we can use a link:{doc-javadoc-url}org/hibernate/context/spi/TenantCredentialsMapper.html[`TenantCredentialsMapper`] to supply the username and password of each tenant.
If each database user has a different default schema, we might not need a `TenantSchemaMapper`.

[discrete]
==== Discriminator-based multi-tenancy

The third option is quite different.
In this case we store data from all tenants in the same tables, but each table has a dedicated column holding the tenant id mapped by each of our entities.

[source,java]
----
@Entity
class Account {
    @Id String id;
    @TenantId String tenantId;
    
    ...
}
----

The link:{doc-javadoc-url}org/hibernate/annotations/TenantId.html[`@TenantId`] annotation is used to indicate an attribute of an entity which holds the tenant id.
Within a given session, our data is automatically filtered so that only rows tagged with the tenant id of the current tenant are visible in that session.

Since Hibernate 8.0, the visibility rules for discriminator-based multi-tenancy are enforced by the database itself on platforms with built-in support for row-level security.
Hibernate automatically generates DDL with the necessary row-level security constraints.
This feature is enabled by default, but may be disabled by setting `hibernate.multi_tenant.rls_enabled=false`.

Here there are two options:

- when a `TenantCredentialsMapper` is supplied via `hibernate.multi_tenant.credentials_mapper`, the tenant id must represent the authenticated database user, and row-level ownership is tied to the current database user, or
- otherwise, when no `TenantCredentialsMapper` is supplied, a transaction-local or session variable is set to the value of the tenant id, and row-level ownership is tied to the value of this variable.

The first option is more secure, but does not work will with some connection pools.

[CAUTION]
====
On databases which don't support row-level security, or when row-level security is disabled, native SQL queries are _not_ automatically filtered by tenant id.
We must add the tenant filtering by hand.
====

[[read-only-replicas]]
=== Read-only replicas

A similar but distinct problem is accessing data held in a read-only replica of the main production database.
One way to handle this problem is to simply instantiate two instances of `SessionFactory`:

- read-only transactions use a `SessionFactory` configured to access the read-only replica, while
- other transactions use the `SessionFactory` configured to read from and write to the main database.

[CAUTION]
====
The second-level cache doesn't play well with replication, and so a `SessionFactory` with access to a read-only replica should be configured with the second-level cache disabled.
====

Alternatively, Hibernate 7.2 introduces experimental support for accessing replicas via a single instance of `SessionFactory`.
A `Session` which accesses a read-only replica must be created in a special read-only mode:

[source,java]
----
Session readOnlySession =
        factory.withOptions()
                .readOnly(true)
                .initialCacheMode(CacheMode.IGNORE)
                .openSession();
----

There are now two possibilities.

- Some JDBC drivers (MySQL) are able to automatically direct read-only sessions to the read-only replica.
  In this case, there's no more work to do, since Hibernate will automatically call `Connection.setReadOnly(true)` to signal to the JDBC driver that the read-only replica may be used.

- Other drivers (Postgres, Oracle) don't feature any special support for read-only replicas, and in this case we need to supply our own custom link:{doc-javadoc-url}/org/hibernate/engine/jdbc/connections/spi/ConnectionProvider.html[`ConnectionProvider`] or link:{doc-javadoc-url}/org/hibernate/engine/jdbc/connections/spi/MultiTenantConnectionProvider.html[`MultiTenantConnectionProvider`] and implement link:{doc-javadoc-url}/org/hibernate/engine/jdbc/connections/spi/ConnectionProvider.html#getReadOnlyConnection()[`getReadOnlyConnection()`] to return a connection to the read-only replica.

Notice that we created the read-only session with link:{doc-javadoc-url}/org/hibernate/CacheMode.html#IGNORE[`CacheMode.IGNORE`], indicating that access to the read-only replica should <<second-level-cache-management,bypass the second-level cache>>.
There's two different phenomena we need to consider here:

1. A read-only replica might contain stale data which has already been updated or deleted from the main database and invalidated in the second-level cache.
A read-only session might read this stale data and recache it, exposing the stale data to subsequent sessions.
Use of `CacheMode.GET` in a read-only session prevents this phenomenon.

2. A session might read data which has not yet been replicated from the main database and add it to the second-level cache.
If a read-only session reads this data from the cache, it might fail to resolve references to other data which has not yet been replicated.
Use of `CacheMode.PUT` in a read-only session prevents this phenomenon.

Use of `CacheMode.IGNORE` in a read-only session prevents both phenomena.

[CAUTION]
====
The first issue is objectively more serious than the second, and the second issue can often be avoided by careful programming by someone _who really understands what they're doing_.
We do not, therefore, require the use of `CacheMode.IGNORE`, but we strongly encourage the use of _at least_ `CacheMode.GET` in every read-only session.
====


[[custom-sql]]
=== Using custom-written SQL

We've already discussed how to run <<native-queries,queries written in SQL>>, but occasionally that's not enough.
Sometimes—but much less often than you might expect—we would like to customize the SQL used by Hibernate to perform basic CRUD operations for an entity or collection.

For this we can use link:{doc-javadoc-url}org/hibernate/annotations/SQLInsert.html[`@SQLInsert`] and friends:

[source,java]
----
@Entity
@SQLInsert(sql = "insert into person (name, id, valid) values (?, ?, true)",
           verify = Expectation.RowCount.class)
@SQLUpdate(sql = "update person set name = ? where id = ?")
@SQLDelete(sql = "update person set valid = false where id = ?")
@SQLSelect(sql = "select id, name from person where id = ? and valid = true")
public static class Person { ... }
----

.Annotations for overriding generated SQL
[%breakable,cols="25,~"]
|===
| Annotation | Purpose

| link:{doc-javadoc-url}org/hibernate/annotations/SQLSelect.html[`@SQLSelect`] | Overrides a generated SQL `select` statement
| link:{doc-javadoc-url}org/hibernate/annotations/SQLInsert.html[`@SQLInsert`] | Overrides a generated SQL `insert` statement
| link:{doc-javadoc-url}org/hibernate/annotations/SQLUpdate.html[`@SQLUpdate`] | Overrides a generated SQL `update` statement
| link:{doc-javadoc-url}org/hibernate/annotations/SQDelete.html[`@SQDelete`] | Overrides a generated SQL `delete` statement for a single row
| link:{doc-javadoc-url}org/hibernate/annotations/SQDeleteAll.html[`@SQDeleteAll`] | Overrides a generated SQL `delete` statement for multiple rows
| link:{doc-javadoc-url}org/hibernate/annotations/SQLRestriction.html[`@SQLRestriction`] | Adds a restriction to generated SQL
| link:{doc-javadoc-url}org/hibernate/annotations/SQLOrder.html[`@SQLOrder`] | Adds an ordering to generated SQL
|===

[TIP]
====
If the custom SQL should be executed via a `CallableStatement`, just specify `callable=true`.
====

Any SQL statement specified by one of these annotations must have exactly the number of JDBC parameters that Hibernate expects, that is, one for each column mapped by the entity, in the exact order Hibernate expects. In particular, the primary key columns must come last.

However, the `@Column` annotation does lend some flexibility here:

- if a column should not be written as part of the custom `insert` statement, and has no corresponding JDBC parameter in the custom SQL, map it `@Column(insertable=false)`, or
- if a column should not be written as part of the custom `update` statement, and has no corresponding JDBC parameter in the custom SQL, map it `@Column(updatable=false)`.

The `verify` member of these annotations specifies a class implementing `Expectation`, allowing customized logic for checking the success of an operation executed via JDBC.
There are three built-in implementations:

- `Expectation.None`, which performs no checks,
- `Expectation.RowCount`, which is what Hibernate usually uses when executing its own generated SQL,
- and `Expectation.OutParameter`, which is useful for checking an output parameter of a stored procedure.

You can write your own implementation of `Expectation` if none of these options is suitable.

[TIP]
====
If you need custom SQL, but are targeting multiple dialects of SQL, you can use the annotations defined in link:{doc-javadoc-url}org/hibernate/annotations/DialectOverride.html[`DialectOverride`].
For example, this annotation lets us override the custom `insert` statement just for PostgreSQL:

[source,java]
----
@DialectOverride.SQLInsert(dialect = PostgreSQLDialect.class,
    override = @SQLInsert(sql="insert into person (name,id) values (?,gen_random_uuid())"))
----
It's even possible to override the custom SQL for specific _versions_ of a database.
====

Sometimes a custom `insert` or `update` statement assigns a value to a mapped column which is calculated when the statement is executed on the database.
For example, the value might be obtained by calling a SQL function:

[source,java]
----
@SQLInsert(sql = "insert into person (name, id) values (?, gen_random_uuid())")
----

But the entity instance which represents the row being inserted or updated won't be automatically populated with that value.
And so our persistence context loses synchronization with the database.
In situations like this, we may use the `@Generated` annotation to tell Hibernate to reread the state of the entity after each `insert` or `update`.

[[database-generated-columns]]
=== Handling database-generated columns

Sometimes, a column value is assigned or mutated by events that happen in the database, and aren't visible to Hibernate.
For example:

- a table might have a column value populated by a trigger,
- a mapped column might have a default value defined in DDL, or
- a custom SQL `insert` or `update` statement might assign a value to a mapped column, as we saw in the previous subsection.

One way to deal with this situation is to explicitly call `refresh()` at appropriate moments, forcing the session to reread the state of the entity.
But this is annoying.

The link:{doc-javadoc-url}org/hibernate/annotations/Generated.html[`@Generated`] annotation relieves us of the burden of explicitly calling `refresh()`.
It specifies that the value of the annotated entity attribute is generated by the database, and that the generated value should be automatically retrieved using a SQL `returning` clause, or separate `select` after it is generated.

A useful example is the following mapping:

[source,java]
----
@Entity
class Entity {
    @Generated @Id
    @ColumnDefault("gen_random_uuid()")
    UUID id;
}
----

The generated DDL is:

[source,sql]
----
create table Entity (
    id uuid default gen_random_uuid() not null,
    primary key (uuid)
)
----

So here the value of `id` is defined by the column default clause, by calling the PostgreSQL function `gen_random_uuid()`.

When a column value is generated during updates, use `@Generated(event=UPDATE)`.
When a value is generated by both inserts _and_ updates, use `@Generated(event={INSERT,UPDATE})`.

[TIP]
====
For columns which should be generated using a SQL `generated always as` clause, prefer the link:{doc-javadoc-url}org/hibernate/annotations/GeneratedColumn.html[`@GeneratedColumn`] annotation, so that Hibernate automatically generates the correct DDL.
====

Actually, the `@Generated` and `@GeneratedColumn` annotations are defined in terms of a more generic and user-extensible framework for handling attribute values generated in Java, or by the database.
So let's drop down a layer, and see how that works.

[[user-defined-generators]]
=== User-defined generators

JPA doesn't define a standard way to extend the set of id generation strategies, but Hibernate does:

- the link:{doc-javadoc-url}org/hibernate/generator/Generator.html[`Generator`] hierarchy of interfaces in the package `org.hibernate.generator` lets you define new generators, and
- the link:{doc-javadoc-url}org/hibernate/annotations/IdGeneratorType.html[`@IdGeneratorType`] meta-annotation from the package `org.hibernate.annotations` lets you write an annotation which associates a `Generator` type with identifier attributes.

Furthermore, the link:{doc-javadoc-url}org/hibernate/annotations/ValueGenerationType.html[`@ValueGenerationType`] meta-annotation lets you write an annotation which associates a `Generator` type with a non-`@Id` attribute.

[NOTE]
// .The older APIs are still available in Hibernate 6
====
These APIs were new in Hibernate 6, and supersede the classic `IdentifierGenerator` interface and `@GenericGenerator` annotation from older versions of Hibernate.
However, the older APIs are still available and custom ``IdentifierGenerator``s written for older versions of Hibernate continue to work in Hibernate 7.
====

Hibernate has a range of built-in generators which are defined in terms of this new framework.

.Built-in generators
[%breakable,cols="20,25,~"]
|===
| Annotation | Implementation | Purpose

| link:{doc-javadoc-url}org/hibernate/annotations/Generated.html[`@Generated`] | `GeneratedGeneration` | Generically handles database-generated values
| link:{doc-javadoc-url}org/hibernate/annotations/GeneratedColumn.html[`@GeneratedColumn`] | `GeneratedAlwaysGeneration` | Handles values generated using `generated always`
| link:{doc-javadoc-url}org/hibernate/annotations/CurrentTimestamp.html[`@CurrentTimestamp`] | `CurrentTimestampGeneration` | Generic support for database or in-memory generation of creation or update timestamps
| link:{doc-javadoc-url}org/hibernate/annotations/CreationTimestamp.html[`@CreationTimestamp`] | `CurrentTimestampGeneration` | A timestamp generated when an entity is first made persistent
| link:{doc-javadoc-url}org/hibernate/annotations/UpdateTimestamp.html[`@UpdateTimestamp`] | `CurrentTimestampGeneration` | A timestamp generated when an entity is made persistent, and regenerated every time the entity is modified
| link:{doc-javadoc-url}org/hibernate/annotations/UuidGenerator.html[`@UuidGenerator`] | `UuidGenerator` | A more flexible generator for RFC 4122 UUIDs
|===

Furthermore, support for JPA's standard id generation strategies is also defined in terms of this framework.

As an example, let's look at how link:{doc-javadoc-url}org/hibernate/annotations/UuidGenerator.html[`@UuidGenerator`] is defined:

[source,java]
----
@IdGeneratorType(org.hibernate.id.uuid.UuidGenerator.class)
@ValueGenerationType(generatedBy = org.hibernate.id.uuid.UuidGenerator.class)
@Retention(RUNTIME)
@Target({ FIELD, METHOD })
public @interface UuidGenerator { ... }
----

`@UuidGenerator` is meta-annotated both `@IdGeneratorType` and `@ValueGenerationType` because it may be used to generate both ids and values of regular attributes.
Either way, link:{doc-javadoc-url}org/hibernate/id/uuid/UuidGenerator.html[this `Generator` class] does the hard work:

[source,java]
----
public class UuidGenerator
        // this generator produced values before SQL is executed
        implements BeforeExecutionGenerator {
    
    // constructors accept an instance of the @UuidGenerator
    // annotation, allowing the generator to be "configured"

    // called to create an id generator
    public UuidGenerator(
            org.hibernate.annotations.UuidGenerator config,
            Member idMember,
            GeneratorCreationContext creationContext) {
        this(config, idMember);
    }

    // called to create a generator for a regular attribute
    public UuidGenerator(
            org.hibernate.annotations.UuidGenerator config,
            Member member,
            GeneratorCreationContext creationContext) {
        this(config, idMember);
    }
    
    ...

    @Override
    public EnumSet<EventType> getEventTypes() {
        // UUIDs are only assigned on insert, and never regenerated
        return INSERT_ONLY;
    }

    @Override
    public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
        // actually generate a UUID and transform it to the required type
        return valueTransformer.transform( generator.generateUuid( session ) );
    }
}
----

You can find out more about custom generators from the Javadoc for `@IdGeneratorType` and for `org.hibernate.generator`.


[[naming-strategies]]
=== Naming strategies

When working with a pre-existing relational schema, it's usual to find that the column and table naming conventions used in the schema don't match Java's naming conventions.

Of course, the `@Table` and `@Column` annotations let us explicitly specify a mapped table or column name.
But we would prefer to avoid scattering these annotations across our whole domain model.

Therefore, Hibernate lets us define a mapping between Java naming conventions, and the naming conventions of the relational schema.
Such a mapping is called a _naming strategy_.

First, we need to understand how Hibernate assigns and processes names.

- _Logical naming_ is the process of applying naming rules to determine the _logical names_ of objects which were not explicitly assigned names in the O/R mapping.
  That is, when there's no `@Table` or `@Column` annotation.
- _Physical naming_ is the process of applying additional rules to transform a logical name into an actual "physical" name that is used in the database.
  For example, the rules might include things like using standardized abbreviations, or trimming the length of identifiers.

Thus, there's two flavors of naming strategy, with slightly different responsibilities.
Hibernate comes with default implementations of these interfaces:


|===
| Flavor | Default implementation

| An link:{doc-javadoc-url}org/hibernate/boot/model/naming/ImplicitNamingStrategy.html[`ImplicitNamingStrategy`] is responsible for assigning a logical name when none is specified by an annotation
| A default strategy which implements the rules defined by JPA
| A link:{doc-javadoc-url}org/hibernate/boot/model/naming/PhysicalNamingStrategy.html[`PhysicalNamingStrategy`] is responsible for transforming a logical name and producing the name used in the database
| A trivial implementation which does no processing
|===

[TIP]
====
We happen to not much like the naming rules defined by JPA, which specify that mixed case and camel case identifiers should be concatenated using underscores.
We bet you could easily come up with a much better `ImplicitNamingStrategy` than that!
(Hint: it should always produce legit mixed case identifiers.)
====

[TIP]
====
The popular link:{doc-javadoc-url}org/hibernate/boot/model/naming/PhysicalNamingStrategySnakeCaseImpl.html[`PhysicalNamingStrategySnakeCaseImpl`] produces snake case identifiers.
====

Custom naming strategies may be enabled using the configuration properties we already mentioned without much explanation back in <<minimizing>>.

.Naming strategy configuration
[%breakable,cols="35,~"]
|===
| Configuration property name           | Purpose

| link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#IMPLICIT_NAMING_STRATEGY[`hibernate.implicit_naming_strategy`]  | Specifies the `ImplicitNamingStrategy`
| link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#PHYSICAL_NAMING_STRATEGY[`hibernate.physical_naming_strategy`]  | Specifies the `PhysicalNamingStrategy`
|===

[[spatial]]
=== Spatial datatypes

:ogc: https://www.ogc.org
:geolatte: https://github.com/GeoLatte/geolatte-geom
:spatial-doc: {doc-user-guide-url}#spatial

Hibernate Spatial augments the <<basic-attributes,built-in basic types>> with a set of Java mappings for {ogc}[OGC] spatial types.

- {geolatte}[Geolatte-geom] defines a set of Java types implementing the OGC spatial types, and codecs for translating to and from database-native spatial datatypes.
- {spatial-doc}[Hibernate Spatial] itself supplies integration with Hibernate.

To use Hibernate Spatial, we must add it as a dependency, as described in <<optional-dependencies>>.

Then we may immediately use Geolatte-geom and JTS types in our entities.
No special annotations are needed:

[source,java]
----
import org.locationtech.jts.geom.Point;
import jakarta.persistence.*;

@Entity
class Event {
    Event() {}

    Event(String name, Point location) {
        this.name = name;
        this.location = location;
    }

    @Id @GeneratedValue
    Long id;

    String name;

    Point location;

}
----

The generated DDL uses `geometry` as the type of the column mapped by `location`:

[source,sql]
----
create table Event (
    id bigint not null,
    location geometry,
    name varchar(255),
    primary key (id)
)
----

Hibernate Spatial lets us work with spatial types just as we would with any of the built-in basic attribute types.

[source,java]
----
var geometryFactory = new GeometryFactory();
...

Point point = geometryFactory.createPoint(new Coordinate(10, 5));
session.persist(new Event("Hibernate ORM presentation", point));
----

But what makes this powerful is that we may write some very fancy queries involving functions of spatial types:

[source,java]
----
Polygon triangle =
        geometryFactory.createPolygon(
                new Coordinate[] {
                        new Coordinate(9, 4),
                        new Coordinate(11, 4),
                        new Coordinate(11, 20),
                        new Coordinate(9, 4)
                }
        );
Point event =
        session.createQuery("select location from Event where within(location, :zone) = true", Point.class)
                .setParameter("zone", triangle)
                .getSingleResult();
----

:matrix: {doc-user-guide-url}#spatial-configuration-dialect-features

Here, `within()` is one of the functions for testing spatial relations defined by the OpenGIS specification.
Other such functions include `touches()`, `intersects()`, `distance()`, `boundary()`, etc.
Not every spatial relation function is supported on every database.
A matrix of support for spatial relation functions may be found in the {matrix}[User Guide].

[TIP]
====
If you want to play with spatial functions on H2, run the following code first:

[source,java]
----
sessionFactory.inTransaction(session -> {
    session.doWork(connection -> {
        try (var statement = connection.createStatement()) {
            statement.execute("create alias if not exists h2gis_spatial for \"org.h2gis.functions.factory.H2GISFunctions.load\"");
            statement.execute("call h2gis_spatial()");
        }
    });
} );
----
====

[[ordered-sorted]]
=== Ordered and sorted collections and map keys

Java lists and maps don't map very naturally to foreign key relationships between tables, and so we tend to avoid using them to represent associations between our entity classes.
But if you feel like you _really_ need a collection with a fancier structure than `Set`, Hibernate does have options.

TIP: For more detail about the use of these annotations, please refer to https://in.relation.to/2024/11/12/-what-collection/[this post on the Hibernate blog].

The following options let us map the index of a `List` or key of a `Map` to a column, and are used with:

- `@ElementCollection`, or
- on the owning side of an association.

They should not be used on the unowned (that is, `mappedBy`) side of an association.

.Annotations for mapping lists and maps
[%breakable,cols="22,~,^13"]
|===
| Annotation | Purpose | JPA-standard

| `@OrderColumn` | Specifies the column used to maintain the order of a list | &#10004;
| link:{doc-javadoc-url}org/hibernate/annotations/ListIndexBase.html[`@ListIndexBase`] | The column value for the first element of the list (zero by default) | &#10006;
| `@MapKeyColumn` | Specifies the column used to persist the keys of a map
(used when the key is of basic type)| &#10004;
| `@MapKeyJoinColumn` | Specifies the column used to persist the keys of a map
(used when the key is an entity) | &#10004;
|===

The name of the `@OrderColumn` or `@MapKeyColumn` may be defaulted, for example:

[source,java]
----
@ManyToMany
@OrderColumn // order of list is persistent
List<Author> authors = new ArrayList<>();
----

But it's usually better to specify the column name explicitly:

[source,java]
----
@ElementCollection
@OrderColumn(name="tag_order")
@ListIndexBase(1) // order column and base value
List<String> tags;
----

Such mappings can get pretty complicated:

[source,java]
----
@ElementCollection
@CollectionTable(name = "author_bios",                 // table name
        joinColumns = @JoinColumn(name = "book_isbn")) // column holding foreign key of owner
@Column(name="bio")                                    // column holding map values
@MapKeyJoinColumn(name="author_ssn")                   // column holding map keys
Map<Author,String> biographies;
----

As you can imagine, we think you should use such mappings very sparingly, if at all.

For a `Map` representing an unowned `@OneToMany` association, the column holding the key of the map must also be mapped on the owning side, usually by an attribute of the target entity.
In this case we use a different annotation:

.Annotation for mapping an entity attribute to a map key
[%breakable,cols="22,~,^13"]
|===
| Annotation | Purpose | JPA-standard

| `@MapKey` | Specifies an attribute of the target entity which acts as the key of the map | &#10004;
|===

Note that `@MapKey` specifies a field or property name, not a column name.

[source,java]
----
@OneToMany(mappedBy = Book_.PUBLISHER)
@MapKey(name = Book_.TITLE) // the key of the map is the title of the book
Map<String,Book> booksByTitle = new HashMap<>();
----

In fact, `@MapKey` may also be used for owned collections.

Now, let's introduce a little distinction:

- an _ordered collection_ is one with an ordering maintained in the database, and
- a _sorted collection_ is one which is sorted in Java code.

These annotations allow us to specify how the elements of a collection should be ordered as they are read from the database:

.Annotations for ordered collections
[%breakable,cols="22,~,^13"]
|===
| Annotation | Purpose | JPA-standard

| `@OrderBy` | Specifies a fragment of JPQL used to order the collection | &#10004;
| `@SQLOrder` | Specifies a fragment of SQL used to order the collection | &#10006;
|===

On the other hand, the following annotations specify how a collection should be sorted in memory, and are used for collections of type `SortedSet` or `SortedMap`:

.Annotations for sorted collections
[%breakable,cols="22,~,^13"]
|===
| Annotation | Purpose | JPA-standard

| link:{doc-javadoc-url}org/hibernate/annotations/SortNatural.html[`@SortNatural`] | Specifies that the elements of a collection are `Comparable` | &#10006;
| link:{doc-javadoc-url}org/hibernate/annotations/SortComparator.html[`@SortComparator`] | Specifies a `Comparator` used to sort the collection | &#10006;
|===

Under the covers, Hibernate uses a `TreeSet` or `TreeMap` to maintain the collection in sorted order.

[CAUTION]
====
The unowned (`mappedBy`) side of a bidirectional association is not responsible for specifying column mappings.
So it's wrong in principle to use `@OrderColumn` or `@MapKeyColumn` on the unowned side of an association mapping.
But for unowned collections, we may use `@OrderBy` or `@MapKey` instead.
That is:

- You can use `@OrderColumn` or `@MapKeyColumn` with an `@ElementCollection`, owned `@ManyToMany`, or owned `@OneToMany`.
- But use `@OrderBy` or `@MapKey` when it's an _unowned_ `@ManyToMany` or `@OneToMany`.
====

[[any]]
=== Any mappings

:any-doc: {doc-user-guide-url}#associations-any

An link:{doc-javadoc-url}org/hibernate/annotations/Any.html[`@Any`] mapping is a sort of polymorphic many-to-one association where the target entity types are not related by the usual entity inheritance.
The target type is distinguished using a discriminator value stored on the _referring_ side of the relationship.

This is quite different to <<entity-inheritance,discriminated inheritance>> where the discriminator is held in the tables mapped by the referenced entity hierarchy.

For example, consider an `Order` entity containing `Payment` information, where a `Payment` might be a `CashPayment` or a `CreditCardPayment`:

[source,java]
----
interface Payment { ... }

@Entity
class CashPayment { ... }

@Entity
class CreditCardPayment { ... }
----

In this example, `Payment` is not be declared as an entity type, and is not annotated `@Entity`. It might even be an interface, or at most just a mapped superclass, of `CashPayment` and `CreditCardPayment`. So in terms of the object/relational mappings, `CashPayment` and `CreditCardPayment` would not be considered to participate in the same entity inheritance hierarchy.

On the other hand, `CashPayment` and `CreditCardPayment` do have the same identifier type.
This is important.


An `@Any` mapping would store the discriminator value identifying the concrete type of `Payment` along with the state of the associated `Order`, instead of storing it in the table mapped by `Payment`.

[source,java]
----
@Entity
class Order {
    ...

    @Any
    @AnyKeyJavaClass(UUID.class)   //the foreign key type
    @JoinColumn(name="payment_id") // the foreign key column
    @Column(name="payment_type")   // the discriminator column
    // map from discriminator values to target entity types
    @AnyDiscriminatorValue(discriminator="CASH", entity=CashPayment.class)
    @AnyDiscriminatorValue(discriminator="CREDIT", entity=CreditCardPayment.class)
    Payment payment;

    ...
}
----

It's reasonable to think of the "foreign key" in an `@Any` mapping as a composite value made up of the foreign key and discriminator taken together. Note, however, that this composite foreign key is only conceptual and cannot be declared as a physical constraint on the relational database table.

There are a number of annotations which are useful to express this sort of complicated and unnatural mapping:

.Annotations for `@Any` mappings
|===
| Annotations | Purpose

| link:{doc-javadoc-url}org/hibernate/annotations/Any.html[`@Any`] | Declares that an attribute is a discriminated polymorphic association mapping
| link:{doc-javadoc-url}org/hibernate/annotations/AnyDiscriminator.html[`@AnyDiscriminator`] | Specify the Java type of the discriminator
| `@JdbcType` or `@JdbcTypeCode` | Specify the JDBC type of the discriminator
| link:{doc-javadoc-url}org/hibernate/annotations/AnyDiscriminatorValue.html[`@AnyDiscriminatorValue`] | Specifies how discriminator values map to entity types
| `@Column` or `@Formula` | Specify the column or formula in which the discriminator value is stored
| `@AnyKeyJavaType` or `@AnyKeyJavaClass` | Specify the Java type of the foreign key (that is, of the ids of the target entities)
| `@AnyKeyJdbcType` or `@AnyKeyJdbcTypeCode` | Specify the JDBC type of the foreign key
| `@JoinColumn` | Specifies the foreign key column
|===

As a general principle, an `@Any` association shares the semantics of `@ManyToAny`, and, since Hibernate 7.4, may be used just like a  `@ManyToOne` in HQL and so on.

Of course, `@Any` mappings are disfavored, except in extremely special cases, since it's much more difficult to enforce referential integrity at the database level.

Further information may be found in the {any-doc}[User Guide].

[[dynamic-insert-update]]
=== Selective column lists in inserts and updates

By default, Hibernate generates `insert` and `update` statements for each entity during boostrap, and reuses the same `insert` statement every time an instance of the entity is made persistent, and the same `update` statement every time an instance of the entity is modified.

This means that:

- if an attribute is `null` when the entity is made persistent, its mapped column is redundantly included in the SQL `insert`, and
- worse, if a certain attribute is unmodified when other attributes are changed, the column mapped by that attribute is redundantly included in the SQL `update`.

Most of the time, this just isn't an issue worth worrying about.
The cost of interacting with the database is _usually_ dominated by the cost of a round trip, not by the number of columns in the `insert` or `update`.
But in cases where it does become important, there are two ways to be more selective about which columns are included in the SQL.

The JPA-standard way is to indicate statically which columns are eligible for inclusion via the `@Column` annotation.
For example, if an entity is always created with an immutable `creationDate`, and with no `completionDate`, then we would write:

[source,java]
----
@Column(updatable=false) LocalDate creationDate;
@Column(insertable=false) LocalDate completionDate;
----

This approach works quite well in many cases, but often breaks down for entities with more than a handful of updatable columns.

An alternative solution is to ask Hibernate to generate SQL dynamically each time an `insert` or `update` is executed.
We do this by annotating the entity class.

.Annotations for dynamic SQL generation
[%breakable,cols="25,~"]
|===
| Annotation | Purpose

| link:{doc-javadoc-url}org/hibernate/annotations/DynamicInsert.html[`@DynamicInsert`] | Specifies that an `insert` statement should be generated each time an entity is made persistent
| link:{doc-javadoc-url}org/hibernate/annotations/DynamicUpdate.html[`@DynamicUpdate`] | Specifies that an `update` statement should be generated each time an entity is modified
|===

It's important to realize that, while `@DynamicInsert` usually has no impact on semantics, the more useful `@DynamicUpdate` annotation _does_ have a subtle side effect.

[CAUTION]
====
The wrinkle is that if an entity has no version property, `@DynamicUpdate` opens the possibility of two optimistic transactions concurrently reading and selectively updating a given instance of the entity.
In principle, this might lead to a row with inconsistent column values after both optimistic transactions commit successfully.
====

Of course, this consideration doesn't arise for entities with a `@Version` attribute.

[TIP]
====
But there's a solution!
Well-designed relational schemas should have _constraints_ to ensure data integrity.
That's true no matter what measures we take to preserve integrity in our program logic.
We may ask Hibernate to add a <<constraints,`check` constraint>> to our table using the `@Check` annotation.
Check constraints and foreign key constraints can help ensure that a row never contains inconsistent column values.
====

[[bytecode-enhancer]]
=== Using the bytecode enhancer

:enhancer: {doc-user-guide-url}#BytecodeEnhancement

Hibernate's {enhancer}[bytecode enhancer] enables the following features:

- _attribute-level lazy fetching_ for basic attributes annotated `@Basic(fetch=LAZY)` and for lazy non-polymorphic associations,
- _interception-based_—instead of the usual _snapshot-based_—detection of modifications.

In addition, use of the bytecode enhancer relaxes the usual requirement that entity and embeddable classes have default constructors.
If a class annotated `@Entity`, `@MappedSuperclass`, or `@Embeddable` has no default constructor, the bytecode enhancer will add it.

To use the bytecode enhancer, we must add the Hibernate plugin to our gradle build:

[source,groovy,subs="attributes+"]
----
plugins {
    id "org.hibernate.orm" version "{fullVersion}"
}

hibernate {
  enhancement {}
}
----

[CAUTION]
====
Some online documentation (including previous versions of the present one) suggest to use `hibernate { enhancement }`, which will _not_ work as it is interpreted by Gradle as a (pointless) getter call instead of actual configuration.
That form will result in bytecode enhancement NOT happening (unfortunately silently).
To enable bytecode enhancement, make sure to always use the block form (with `{}`).
====

// [discrete]
// ==== Attribute-level lazy fetching

Consider this field:

[source,java]
----
@Entity
class Book {
    ...

    @Basic(optional = false, fetch = LAZY)
    @Column(length = LONG32)
    String fullText;
    
    ...
}
----

The `fullText` field maps to a `clob` or `text` column, depending on the SQL dialect.
Since it's expensive to retrieve the full book-length text, we've mapped the field `fetch=LAZY`, telling Hibernate not to read the field until it's actually used.

- _Without_ the bytecode enhancer, this instruction is ignored, and the field is always fetched immediately, as part of the initial `select` that retrieves the `Book` entity.
- _With_ bytecode enhancement, Hibernate is able to detect access to the field, and lazy fetching is possible.

[TIP]
====
By default, Hibernate fetches all lazy fields of a given entity at once, in a single `select`, when any one of them is accessed.
Using the link:{doc-javadoc-url}org/hibernate/annotations/LazyGroup.html[`@LazyGroup`] annotation, it's possible to assign fields to distinct "fetch groups", so that different lazy fields may be fetched independently.
====

Similarly, interception lets us implement lazy fetching for non-polymorphic associations without the need for a separate proxy object.
However, if an association is polymorphic, that is, if the target entity type has subclasses, then a proxy is still required.

// [discrete]
// ==== Interception-based change detection

Interception-based change detection is a nice performance optimization with a slight cost in terms of correctness.

- _Without_ the bytecode enhancer, Hibernate keeps a snapshot of the state of each entity after reading from or writing to the database.
When the session flushes, the snapshot state is compared to the current state of the entity to determine if the entity has been modified.
Maintaining these snapshots does have an impact on performance.
- _With_ bytecode enhancement, we may avoid most of this cost by intercepting writes to the field and recording these modifications as they happen--however, a snapshot is still maintained for any field whose value is itself mutable, for example, for a field of type `byte[]`.

This optimization isn't _completely_ transparent, however.

[CAUTION]
====
Interception-based change detection is less accurate than snapshot-based dirty checking.
In particular, writes to a field of an enhanced entity from outside the entity class itself are not detected by the enhanced bytecode and might not be made persistent.
====

[IMPORTANT]
Hibernate's extended bytecode enhancement feature has been deprecated, primarily because it relies on assumptions and behaviors that often require a broader runtime scope than what Hibernate alone can reliably provide, similar to container-based environments such as Quarkus or WildFly.
Applications which make use of this feature should instead use proper object-oriented encapsulation, exposing managed state via getters and setters.

[[fetch-profiles]]
=== Named fetch profiles

We've already seen two different ways to override the default <<association-fetching,fetching strategy>> for an association:

- <<entity-graph,JPA entity graphs>>, and
- the `join fetch` clause in <<hql-queries,HQL>>, or, equivalently, the method `From.fetch()` in the criteria query API.

A third way is to define a named fetch profile.
First, we must declare the profile, by annotating a class, package, or module link:{doc-javadoc-url}org/hibernate/annotations/FetchProfile.html[`@FetchProfile`]:

[source,java]
----
@FetchProfile(name = "EagerBook")
@Entity
class Book { ... }
----

Note that even though we've placed this annotation on the `Book` entity, a fetch profile—unlike an entity graph—isn't "rooted" at any particular entity.

We may specify association fetching strategies using the `fetchOverrides` member of the `@FetchProfile` annotation, but frankly it looks so messy that we're embarrassed to show it to you here.

[NOTE]
====
Similarly, a JPA <<entity-graph,entity graph>> may be defined using `@NamedEntityGraph`.
But the format of this annotation is _even worse_ than `@FetchProfile(fetchOverrides=...)`, so we can't recommend it. 💀
====

A better way is to annotate an association with the fetch profiles it should be fetched in:

[source,java]
----
@FetchProfile(name = "EagerBook")
@Entity
class Book {
    ...

    @ManyToOne(fetch = LAZY)
    @FetchProfileOverride(profile = Book_.PROFILE_EAGER_BOOK, mode = JOIN)
    Publisher publisher;

    @ManyToMany
    @FetchProfileOverride(profile = Book_.PROFILE_EAGER_BOOK, mode = JOIN)
    Set<Author> authors;

    ...
}
----
[source,java]
----
@Entity
class Author {
    ...

    @OneToOne
    @FetchProfileOverride(profile = Book_.PROFILE_EAGER_BOOK, mode = JOIN)
    Person person;

    ...
}
----

Here, once again, `Book_.PROFILE_EAGER_BOOK` is generated by Hibernate Processor, and is just a constant with the value `"EagerBook"`.

We may even request subselect fetching:

[source,java]
----
@FetchProfile(name = "EagerBook")
@FetchProfile(name = "BookWithAuthorsBySubselect")
@Entity
class Book {
    ...

    @OneToOne
    @FetchProfileOverride(profile = Book_.PROFILE_EAGER_BOOK, mode = JOIN)
    Person person;

    @ManyToMany
    @FetchProfileOverride(profile = Book_.PROFILE_EAGER_BOOK, mode = JOIN)
    @FetchProfileOverride(profile = Book_.BOOK_WITH_AUTHORS_BY_SUBSELECT,
                          mode = SUBSELECT)
    Set<Author> authors;

    ...
}
----

We may define as many different fetch profiles as we like.

.Annotations for defining fetch profiles
[%breakable,cols="25,~"]
|===
| Annotation | Purpose

| `@FetchProfile` | Declares a named fetch profile, optionally including a list of ``@FetchOverride``s
| `@FetchProfile.FetchOverride` | Declares a fetch strategy override as part of the `@FetchProfile` declaration
| `@FetchProfileOverride` | Specifies the fetch strategy for the annotated association, in a given fetch profile
|===

A fetch profile must be explicitly enabled for a given session by passing the name of the profile to link:{doc-javadoc-url}org/hibernate/Session.html#enableFetchProfile(java.lang.String)[`enableFetchProfile()`]:

[source,java]
----
session.enableFetchProfile(Book_.PROFILE_EAGER_BOOK);
Book eagerBook = session.find(Book.class, bookId);
----

Alternatively, an instance of link:{doc-javadoc-url}org/hibernate/EnabledFetchProfile.html[`EnabledFetchProfile`] may be obtained in a type safe way from the static metamodel, and applied to the session:

[source,java]
----
Book_._EagerBook.enable(session);
Book eagerBook = session.find(Book.class, bookId);
----

Even better, the `EnabledFetchProfile` may be passed as a `FindOption`:

[source,java]
----
Book eagerBook = entityManager.find(Book.class, bookId, Book_._EagerBook);
----

So why or when might we prefer named fetch profiles to entity graphs?
Well, it's really hard to say.
It's nice that this feature _exists_, and if you love it, that's great.
But Hibernate offers alternatives that we think are more compelling most of the time.

[%unbreakable]
[TIP]
====
There's a special built-in fetch profile named `org.hibernate.defaultProfile` which is defined as the profile with `@FetchProfileOverride(mode=JOIN)` applied to every eager `@ManyToOne` or `@OneToOne` association.
If you enable this profile:

[source,java]
----
entityManager.addOption(new EnabledFetchProfile("org.hibernate.defaultProfile"));
----

Then ``outer join``s for such associations will _automatically_ be added to every HQL or criteria query.
This is nice if you can't be bothered typing out those ``join fetch``es explicitly.
And in principle it even helps partially mitigate the <<lazy-problem,problem>> of JPA having specified the wrong default for the `fetch` member of `@ManyToOne`.
====

---

### Documentation Src Main Asciidoc Introduction Configuration (`documentation/src/main/asciidoc/introduction/Configuration.adoc`)

[[configuration]]
== Configuration and bootstrap

:data: https://jakarta.ee/specifications/data/1.1/jakarta-data-1.1-m3.pdf
:persistence: https://jakarta.ee/specifications/persistence/4.0/jakarta-persistence-spec-4.0-M4.pdf

We would love to make this section short.
Unfortunately, there are several distinct ways to configure and bootstrap Hibernate, and we're going to have to describe at least two of them in detail.

The five basic ways to obtain an instance of Hibernate are shown in the following table:

[%breakable,cols="50,50",number=0]
|===

| Using the standard JPA-defined XML, and the operation `Persistence.createEntityManagerFactory()`
| Usually chosen when portability between JPA implementations is important.

| Using the standard JPA-defined  `PersistenceConfiguration` class
| Usually chosen when portability between JPA implementations is important, but programmatic control is desired.

| Using link:{doc-javadoc-url}org/hibernate/jpa/HibernatePersistenceConfiguration.html[`HibernatePersistenceConfiguration`]
// or the older link:{doc-javadoc-url}org/hibernate/cfg/Configuration.html[`Configuration`] class
to construct a `SessionFactory`
| When portability between JPA implementations is not important, this option adds some convenience and saves a typecast.

| Using the more complex APIs defined in link:{doc-javadoc-url}org/hibernate/boot/package-summary.html[`org.hibernate.boot`]
| Used primarily by framework integrators, this option is outside the scope of this document.

| By letting the container take care of the bootstrap process and of injecting the `EntityManagerFactory`
| Used in a container environment like WildFly or Quarkus.
|===

Here we'll focus on the first two options.

:hibernate-quarkus: https://quarkus.io/guides/hibernate-orm

[NOTE]
====
Actually, the last option is extremely popular, since every major Java application server and microservice framework comes with built-in support for Hibernate.
Such container environments typically also feature facilities to automatically manage the lifecycle of an `EntityManager` and its association with container-managed transactions.

To learn how to configure Hibernate in such a container environment, you'll need to refer to the documentation of your chosen container.
For Quarkus, here's the {hibernate-quarkus}[relevant documentation].
====

If you're using Hibernate outside of a container environment,
you'll need to:

- include Hibernate ORM itself, along with the appropriate JDBC driver, as dependencies of your project, and
- configure Hibernate with information about your database,
by specifying configuration properties.

[[required-dependencies]]
=== Including Hibernate in your project build

First, add the following dependency to your project:

----
org.hibernate.orm:hibernate-core:{version}
----

Where `{version}` is the version of Hibernate you're using, `{fullVersion}`, for example.

You'll also need to add a dependency for the JDBC
driver for your database.

.JDBC driver dependencies
[%breakable,cols="50,~"]
|===
| Database                  | Driver dependency

| PostgreSQL or CockroachDB | `org.postgresql:postgresql:{version}`
| MySQL or TiDB             | `com.mysql:mysql-connector-j:{version}`
| MariaDB                   | `org.mariadb.jdbc:mariadb-java-client:{version}`
| DB2                       | `com.ibm.db2:jcc:{version}`
| SQL Server                | `com.microsoft.sqlserver:mssql-jdbc:{version}`
| Oracle                    | `com.oracle.database.jdbc:ojdbc17:{version}`
| Informix                  | `com.informix.jdbc.IfxDriver:{version}`
| H2                        | `com.h2database:h2:{version}`
| HSQLDB                    | `org.hsqldb:hsqldb:{version}`
| MongoDB                   | The JDBC driver is bundled with the dialect mentioned in <<optional-dependencies>>
| Google Spanner            | `com.google.cloud:google-cloud-spanner-jdbc:{version}`
|===

Where `{version}` is the latest version of the JDBC driver for your database.

[[optional-dependencies]]
=== Optional dependencies

:slf4j: http://www.slf4j.org/
:enhancer: {doc-user-guide-url}#tooling-gradle
:agroal: https://agroal.github.io
:jackson: https://github.com/FasterXML/jackson
:yasson: https://projects.eclipse.org/projects/ee4j.yasson
:validator: https://hibernate.org/validator
:ehcache: https://www.ehcache.org
:infinispan: https://infinispan.org
:generator: https://hibernate.org/orm/tooling/
:caffeine: https://github.com/ben-manes/caffeine/
:bean-validation: https://beanvalidation.org
:query-validator: https://github.com/hibernate/query-validator/

Optionally, you might also add any of the following additional features:

.Optional dependencies
[%breakable,cols="50,~"]
|===
| Optional feature | Dependencies

| An {slf4j}[SLF4J] logging implementation |
`org.apache.logging.log4j:log4j-core` +
or `org.slf4j:slf4j-jdk14`
| A JDBC connection pool, for example, {agroal}[Agroal] | `org.hibernate.orm:hibernate-agroal`
| The {generator}[Hibernate Processor], especially if you're using Jakarta Data or the JPA criteria query API | `org.hibernate.orm:hibernate-processor`
| {data}[Jakarta Data] stateless and stateful repository support |
`jakarta.data:jakarta.data-api` +
and `jakarta.data:jakarta.data.stateful-api`
// | The {query-validator}[Query Validator], for compile-time checking of HQL | `org.hibernate:query-validator`
| {validator}[Hibernate Validator], an implementation of {bean-validation}[Bean Validation] |
`org.hibernate.validator:hibernate-validator` +
and `org.glassfish.expressly:expressly`
| Local second-level cache support via JCache and {ehcache}[EHCache] | `org.hibernate.orm:hibernate-jcache` +
and `org.ehcache:ehcache`
| Local second-level cache support via JCache and {caffeine}[Caffeine]| `org.hibernate.orm:hibernate-jcache` +
and `com.github.ben-manes.caffeine:jcache`
| Distributed second-level cache support via {infinispan}[Infinispan] | `org.infinispan:infinispan-hibernate-cache-v60`
// | SCRAM authentication support for PostgreSQL | `com.ongres.scram:client:2.1`
| A JSON serialization library for working with JSON datatypes, for example, {jackson}[Jackson] or {yasson}[Yasson] |
`tools.jackson.core:jackson-databind` +
or `org.eclipse:yasson`
| <<spatial,Hibernate Spatial>> | `org.hibernate.orm:hibernate-spatial`
// | <<envers,Envers>>, deprecated since Hibernate ORM 8.0, for auditing historical data | `org.hibernate.orm:hibernate-envers`
| <<jfr,Hibernate JFR>>, for monitoring via Java Flight Recorder | `org.hibernate.orm:hibernate-jfr`
| Hibernate Jandex integration, for <<entity-discovery,entity discovery>> | `org.hibernate.orm:hibernate-scan-jandex`
| link:{doc-dialect-url}#community-dialects[Community dialects] | `org.hibernate.orm:hibernate-community-dialects`
| https://github.com/mongodb/mongo-hibernate/[MongoDB] dialect | `org.mongodb:mongodb-hibernate`
| https://github.com/GoogleCloudPlatform/google-cloud-spanner-hibernate[Google Spanner] dialect | `com.google.cloud:google-cloud-spanner-hibernate-dialect`
|===

You might also add the Hibernate {enhancer}[bytecode enhancer] to your
Gradle build if you want to use <<bytecode-enhancer,field-level lazy fetching>>.

[[configuration-jpa]]
=== Configuration using JPA XML

Sticking to the JPA-standard approach, we would provide a file named `persistence.xml`, which we usually place in the `META-INF` directory of a _persistence archive_, that is, of the `.jar` file or directory which contains our entity classes.

[source,xml]
----
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_4_0.xsd"
             version="4.0">

    <persistence-unit name="org.hibernate.example">

        <class>org.hibernate.example.Book</class>
        <class>org.hibernate.example.Author</class>

        <default-to-one-fetch-type>LAZY</default-to-one-fetch-type>

        <properties>
            
            <property name="jakarta.persistence.jdbc.url"
                      value="jdbc:postgresql://localhost/example"/>

            
            <property name="jakarta.persistence.jdbc.user"
                      value="gavin"/>
            <property name="jakarta.persistence.jdbc.password"
                      value="hibernate"/>

            
            <property name="jakarta.persistence.schema-generation.database.action"
                      value="drop-and-create"/>

            
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.highlight_sql" value="true"/>

        </properties>

    </persistence-unit>

</persistence>
----
The `<persistence-unit>` element defines a named _persistence unit_, that is:

- a collection of associated entity types, along with
- a set of default configuration settings, which may be augmented or overridden at runtime.

Each `<class>` element specifies the fully qualified name of an entity class.
In some container environments, for example, in any EE container, the `<class>` elements are unnecessary, as we explain <<entity-discovery,below>>.

The `<default-to-one-fetch-type>` element specifies that many-to-one and one-to-one associations default to <<proxies-and-lazy-fetching,lazy fetching>>.
As <<lazy-problem,explained later>>, we strongly recommend this setting in all new code.

Each `<property>` element specifies a _configuration property_ and its value.
Note that:

- the configuration properties in the `jakarta.persistence` namespace are standard properties defined by the JPA spec, and
- properties in the `hibernate` namespace are specific to Hibernate.

We may obtain an `EntityManagerFactory` by calling `Persistence.createEntityManagerFactory()`:

[source,java]
----
EntityManagerFactory entityManagerFactory =
        Persistence.createEntityManagerFactory("org.hibernate.example");
----

If necessary, we may override configuration properties specified in `persistence.xml`:

[source,java]
----
EntityManagerFactory entityManagerFactory =
        Persistence.createEntityManagerFactory("org.hibernate.example",
                Map.of(Persistence.ConnectionProperties.JDBC_PASSWORD, password));
----

[[configuration-api]]
=== Programmatic configuration using JPA API

The `PersistenceConfiguration` class allows full programmatic control over creation of the `EntityManagerFactory`.

[source,java]
----
EntityManagerFactory entityManagerFactory =
        new PersistenceConfiguration("Bookshop")
            // all associations should be lazy by default
            .defaultToOneFetchType(FetchType.LAZY)
            // register the entity classes
            .managedClass(Book.class)
            .managedClass(Author.class)
            // PostgreSQL
            .property(PersistenceConfiguration.JDBC_URL, "jdbc:postgresql://localhost/example")
            // Credentials
            .property(PersistenceConfiguration.JDBC_USER, user)
            .property(PersistenceConfiguration.JDBC_PASSWORD, password)
            // SQL statement logging
            .property(JdbcSettings.SHOW_SQL, true)
            .property(JdbcSettings.FORMAT_SQL, true)
            .property(JdbcSettings.HIGHLIGHT_SQL, true)
            // Automatic schema export
            .schemaManagementDatabaseAction(SchemaManagementAction.DROP_AND_CREATE)
            // Create a new EntityManagerFactory
            .createEntityManagerFactory();
----

The `defaultToOneFetchType()` method specifies that many-to-one and one-to-one associations default to <<proxies-and-lazy-fetching,lazy fetching>>.
As <<lazy-problem,explained later>>, we strongly recommend this setting in all new code.

The specification gives JPA implementors like Hibernate explicit permission to extend this class, and so Hibernate offers the link:{doc-javadoc-url}org/hibernate/jpa/HibernatePersistenceConfiguration.html[`HibernatePersistenceConfiguration`], which lets us obtain a `SessionFactory` without any need for a cast.footnote:[Alternatively, the venerable class link:{doc-javadoc-url}org/hibernate/cfg/Configuration.html[`Configuration`] offers similar functionality.]

[source,java]
----
SessionFactory sessionFactory =
        new HibernatePersistenceConfiguration("Bookshop")
            // all associations should be lazy by default
            .defaultToOneFetchType(FetchType.LAZY)
            // register the entity classes
            .managedClasses(Book.class, Author.class)
            // PostgreSQL
            .jdbcUrl("jdbc:postgresql://localhost/example")
            // Credentials
            .jdbcCredentials(user, password)
            // SQL statement logging
            .showSql(true, true, true)
            // Automatic schema export
            .schemaManagementDatabaseAction(SchemaManagementAction.DROP_AND_CREATE)
            // Create a new SessionFactory
            .createEntityManagerFactory();
----

:native-bootstrap: {doc-user-guide-url}#bootstrap-native
:boot: {doc-javadoc-url}/org/hibernate/boot/package-summary.html

.*Read more: Advanced configuration options*
[%collapsible]
====
****
Actually, these APIs are very simple facades resting on the much more powerful--but also more complex--APIs defined in the package `org.hibernate.boot`.
This API is useful if you have very advanced requirements, for example, if you're writing a framework or implementing a container.
You'll find more information in the {native-bootstrap}[User Guide], and in the {boot}[package-level documentation] of `org.hibernate.boot`.
****
====

[[entity-discovery]]
=== Entity discovery

In a Jakarta EE container environment, we don't usually need to list entity and embeddable classes explicitly in `persistence.xml`.
Instead, the container scans the persistence unit `jar` file and automatically discovers classes annotated `@Entity`, `@Embeddable`, or `@MappedSuperclass`.

`HibernatePersistenceConfiguration` offers the same functionality if the <<optional-dependencies,optional dependency>> `hibernate-scan-jandex` is available at runtime.

In the following code, entity classes available on the class loader which loaded `Main.class` are automatically discovered.

[source,java]
----
SessionFactory sessionFactory =
        // entities discovered on ClassLoader of Main.class
        new HibernatePersistenceConfiguration("Bookshop", Main.class)
            // PostgreSQL
            .jdbcUrl("jdbc:postgresql://localhost/example")
            // Credentials
            .jdbcCredentials(user, password)
            // SQL statement logging
            .showSql(true, true, true)
            // Automatic schema export
            .schemaManagementDatabaseAction(SchemaManagementAction.DROP_AND_CREATE)
            // Create a new SessionFactory
            .createEntityManagerFactory();
----

Notice that we were able to remove the calls to `managedClass()`.

[[configuration-properties]]
=== Configuration using Hibernate properties file

If we're using programmatic configuration, but we don't want to put certain configuration properties directly in the Java code, we can specify them in a file named `hibernate.properties`, and place the file in the root classpath.

[source,properties]
----
# PostgreSQL
jakarta.persistence.jdbc.url=jdbc:postgresql://localhost/example
# Credentials
jakarta.persistence.jdbc.user=hibernate
jakarta.persistence.jdbc.password=zAh7mY$2MNshzAQ5

# SQL statement logging
hibernate.show_sql=true
hibernate.format_sql=true
hibernate.highlight_sql=true
----

[[basic-configuration-settings]]
=== Basic configuration settings

The inner interfaces of the `Persistence` class -- which, for convenience, are inherited by `PersistenceConfiguration` -- declare `static final` constants holding the names of all configuration properties defined by the specification itself.
For example, `Persistence.ConnectionProperties.JDBC_URL` holds the property name `"jakarta.persistence.jdbc.driver"`.

Similarly, the class link:{doc-javadoc-url}org/hibernate/cfg/AvailableSettings.html[`AvailableSettings`] enumerates all the configuration properties understood by Hibernate.

Of course, we're not going to cover every useful configuration setting in this chapter.
Instead, we'll mention the ones you need to get started, and come back to some other important settings later, especially when we talk about performance tuning.

[TIP]
====
Hibernate has many--too many--switches and toggles.
Please don't go crazy messing about with these settings; most of them are rarely needed, and many only exist to provide backward compatibility with older versions of Hibernate.
With rare exception, the default behavior of every one of these settings was carefully chosen to be _the behavior we recommend_.
====

The properties you really do need to get started are these three:

.JDBC connection settings
[%breakable,cols="35,~"]
|===
| Configuration property name | Purpose

| `jakarta.persistence.jdbc.url` | JDBC URL of your database
| `jakarta.persistence.jdbc.user` and `jakarta.persistence.jdbc.password` | Your database credentials
|===

[IMPORTANT]
// .You don't need `hibernate.dialect` anymore!
====
Since Hibernate 6, you don't need to specify `hibernate.dialect`.
The correct Hibernate SQL `Dialect` will be determined for you automatically.
The only reason to specify this property is if you're using a custom user-written or link:{doc-dialect-url}#third-party-dialects[third-party] `Dialect` class.

Similarly, neither `hibernate.connection.driver_class` nor `jakarta.persistence.jdbc.driver` is needed when working with one of the supported databases.
====

In some environments it's useful to be able to start Hibernate without accessing the database.
In this case, we must explicitly specify not only the database platform, but also the version of the database, using the standard JPA configuration properties.

[source,properties]
----
# disable use of JDBC database metadata
hibernate.boot.allow_jdbc_metadata_access=false

# explicitly specify database and version
jakarta.persistence.database-product-name=PostgreSQL
jakarta.persistence.database-major-version=15
jakarta.persistence.database-minor-version=7
----

The product name is the value returned by `java.sql.DatabaseMetaData.getDatabaseProductName()`, for example, `PostgreSQL`, `MySQL`, `H2`, `Oracle`, `EnterpriseDB`, `MariaDB`, or `Microsoft SQL Server`.

.Settings needed when database is inaccessible at startup
[%breakable,cols="50,~"]
|===
| Configuration property name | Purpose

| `hibernate.boot.allow_jdbc_metadata_access` | Set to `false` to disallow access to the database at startup
| `jakarta.persistence.database-product-name` | The database product name, according to the JDBC driver
| `jakarta.persistence.database-major-version` and `jakarta.persistence.database-minor-version` | The major and minor versions of the database
|===

Pooling JDBC connections is an extremely important performance optimization.
You can set the size of Hibernate's built-in connection pool using this property:

.Built-in connection pool size
[%breakable,cols="35,~"]
|===
| Configuration property name | Purpose

| `hibernate.connection.pool_size` | The size of the connection pool
|===

This configuration property is also respected when you use Agroal, HikariCP, or c3p0 for connection pooling.

[CAUTION]
// .The default connection pool is not meant for production use
====
By default, Hibernate uses a simplistic built-in connection pool.
This pool is not meant for use in production, and later, when we discuss performance, we'll see how to <<connection-pool,select a more robust implementation>>.
====

Alternatively, in a container environment, you'll need at least one of these properties:

.Transaction management settings
[%breakable,cols="35,~"]
|===
| Configuration property name            | Purpose

| `jakarta.persistence.transactionType`  | (Optional, defaults to `JTA`)
                                           Determines if transaction management is via JTA or resource-local transactions.
                                           Specify `RESOURCE_LOCAL` if JTA should not be used.
| `jakarta.persistence.jtaDataSource`    | JNDI name of a JTA datasource
| `jakarta.persistence.nonJtaDataSource` | JNDI name of a non-JTA datasource
|===

In this case, Hibernate obtains pooled JDBC database connections from a container-managed `DataSource`.

[[automatic-schema-export]]
=== Automatic schema export

You can have Hibernate infer your database schema from the mapping annotations you've specified in your Java code, and export the schema at initialization time by specifying one or more of the following configuration properties:

.Schema management settings
[%breakable,cols="50,~"]
|===
| Configuration property name                                | Purpose

| `jakarta.persistence.schema-generation.database.action`
a| * If `drop-and-create`, first drop the schema, then export tables, sequences, and constraints, and then populate initial data
* If `create`, export tables, sequences, and constraints, without attempting to drop them first, and then populate initial data
* If `create-drop`, drop the schema and recreate it on factory startup;
additionally, drop the schema on factory shutdown
* If `drop`, drop the schema on factory startup
* If `validate`, validate the database schema without changing it
* If `update`, only export what's missing in the schema, and alter incorrect column types
* If `populate`, only populate initial data

| `jakarta.persistence.create-database-schemas`
| (Optional) If `true`, automatically create schemas and catalogs

| `jakarta.persistence.schema-generation.create-source`
| (Optional) If `metadata-then-script` or `script-then-metadata`, execute an additional SQL script when exported tables and sequences

| `jakarta.persistence.schema-generation.create-script-source`
| (Optional) The name of a SQL DDL script to be executed

| `jakarta.persistence.sql-load-script-source`
| (Optional) The name of a SQL DML script to be executed

| `hibernate.hbm2ddl.import_files_sql_extractor`
| (Optional) If `multi-line`, SQL statements may be split across multiple lines in scripts, and must be ``;``-terminated.
|===

This feature is extremely useful for testing.

[TIP]
// .Importing test or reference data
====
The easiest way to pre-initialize a database with test or "reference" data is to place a list of SQL `insert` statements in a file named, for example, `import.sql`, and specify the path to this file using the property `jakarta.persistence.sql-load-script-source`.
We've already seen an <<import.sql,example>> of this approach, which is cleaner than writing Java code to instantiate entity instances and calling `persist()` on each of them.
====

As we mentioned <<testing,earlier>>, it can also be useful to control schema export programmatically.

[TIP]
// .Programmatic schema export
====
The link:{doc-javadoc-url}org/hibernate/relational/SchemaManager.html[`SchemaManager`] API allows programmatic control over schema export:

[source,java]
sessionFactory.getSchemaManager().create(true);
====

[[logging-generated-sql]]
=== Logging the generated SQL

:log4j: https://github.com/hibernate/hibernate-reactive/blob/main/examples/session-example/src/main/resources/log4j2.properties

To see the generated SQL as it's sent to the database, we have two options.

One way is to set the property `hibernate.show_sql` to `true`, so that Hibernate logs SQL directly to the console.
You can make the output much more readable by enabling formatting or highlighting.
These settings really help when troubleshooting the generated SQL statements.

.Settings for SQL logging to the console
[%breakable,cols="35,~"]
|===
| Configuration property name | Purpose

| `hibernate.show_sql`        | If `true`, log SQL directly to the console
| `hibernate.format_sql`      | If `true`, log SQL in a multiline, indented format
| `hibernate.highlight_sql`   | If `true`, log SQL with syntax highlighting via ANSI escape codes
|===

Alternatively, you can enable ``DEBUG``-level logging for the category `org.hibernate.SQL` using your preferred SLF4J logging implementation.

For example, if you're using Log4J 2 (as above in <<optional-dependencies>>), add these lines to your `log4j2.properties` file:

[source,properties]
----
# SQL execution
logger.hibernate.name = org.hibernate.SQL
logger.hibernate.level = debug

# JDBC parameter binding
logger.jdbc-bind.name=org.hibernate.orm.jdbc.bind
logger.jdbc-bind.level=trace
# JDBC result set extraction
logger.jdbc-extract.name=org.hibernate.orm.jdbc.extract
logger.jdbc-extract.level=trace

# JDBC batching
logger.jdbc-batch.name=org.hibernate.orm.jdbc.batch
logger.jdbc-batch.level=trace
----

SQL logging respects the settings `hibernate.format_sql` and `hibernate.highlight_sql`, so we don't miss out on the pretty formatting and highlighting.

[[minimizing]]
=== Minimizing repetitive mapping information

The following properties are very useful for minimizing the amount of information you'll need to explicitly specify in `@Table` and `@Column` annotations, which we'll discuss below in <<object-relational-mapping>>:

.Settings for minimizing explicit mapping information
[%breakable,cols="35,~"]
|===
| Configuration property name           | Purpose

| link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#DEFAULT_SCHEMA[`hibernate.default_schema`]            | A default schema name for entities which do not explicitly declare one
| link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#DEFAULT_CATALOG[`hibernate.default_catalog`]           | A default catalog name for entities which do not explicitly declare one
| link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#PHYSICAL_NAMING_STRATEGY[`hibernate.physical_naming_strategy`]  | A `PhysicalNamingStrategy` implementing your database naming standards
| link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#IMPLICIT_NAMING_STRATEGY[`hibernate.implicit_naming_strategy`]  | An `ImplicitNamingStrategy` which specifies how "logical" names of relational objects should be inferred when no name is specified in annotations
|===

[TIP]
// .Implement your naming standards as a `PhysicalNamingStrategy`
====
Writing your own `PhysicalNamingStrategy` and/or `ImplicitNamingStrategy` is an especially good way to reduce the clutter of annotations on your entity classes, and to implement your database naming conventions, and so we think you should do it for any nontrivial data model.
We'll have more to say about them in <<naming-strategies>>.
====

[[quoted-identifiers]]
=== Quoting SQL identifiers

By default, Hibernate never quotes a SQL table or column name in generated SQL when the name contains only alphanumeric characters.
This behavior is usually much more convenient, especially when working with a legacy schema, since unquoted identifiers aren't case-sensitive, and so Hibernate doesn't need to know or care whether a column is named `NAME`, `name`, or `Name` on the database side.
On the other hand, any table or column name containing a punctuation character, or with an initial `$` is automatically quoted by default.

The following settings enable additional automatic quoting:

.Settings for identifier quoting
[%breakable,cols="35,~"]
|===
| Configuration property name           | Purpose

| link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#KEYWORD_AUTO_QUOTING_ENABLED[`hibernate.auto_quote_keyword`]          | Automatically quote any identifier which is a SQL keyword
| link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#GLOBALLY_QUOTED_IDENTIFIERS[`hibernate.globally_quoted_identifiers`] | Automatically quote every identifier
|===

Note that `hibernate.globally_quoted_identifiers` is a synonym for `<delimited-identifiers/>` in the `orm.xml` mapping file.
We don't recommend the use of global identifier quoting, and in fact these settings are rarely used.

[TIP]
====
A better alternative is to explicitly quote table and column names where necessary, by writing `@Table(name="\"View\")` or `@Column(name="\"number\"")`.
Since that's kinda ugly, Hibernate lets us use a backtick as the quote character instead of the double quote.
====

[[nationalized-chars]]
=== Nationalized character data in SQL Server

_By default,_ SQL Server's `char` and `varchar` types don't accommodate Unicode data.
But a Java string may contain any Unicode character.
So, if you're working with SQL Server, you might need to force Hibernate to use the `nchar` and `nvarchar` column types.

.Setting the use of nationalized character data
[%breakable,cols="40,~"]
|===
| Configuration property name                 | Purpose

| link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#USE_NATIONALIZED_CHARACTER_DATA[`hibernate.use_nationalized_character_data`] | Use `nchar` and `nvarchar` instead of `char` and `varchar`
|===

On the other hand, if only _some_ columns store nationalized data, use the link:{doc-javadoc-url}org/hibernate/annotations/Nationalized.html[`@Nationalized`] annotation to indicate fields of your entities which map these columns.

[TIP]
// .Configuring SQL Server to use UTF-8 by default
====
Alternatively, you can configure SQL Server to use the UTF-8 enabled collation `_UTF8`.
====

[[datetime-jdbc]]
=== Date and time types and JDBC

Hibernate highly recommends that applications use `java.time` types to represent temporal-related values.
When `java.time` types are used, Hibernate will by default use those types directly at the JDBC boundary
where the configured Dialect reports that the exact Java class is supported by the driver.
JDBC drivers are required to directly support `java.time` types since Java 8 (JDBC 4.2).

When the Dialect reports that a requested type is unsupported, Hibernate falls back to the corresponding
legacy JDBC representation and logs the known driver/database limitation.  This capability is resolved
separately for each Java Time class, with `OffsetTime` and `OffsetDateTime` treated as a matched pair.

[NOTE]
====
This is a change since version 8.0.  Previous versions, by default, would perform a conversion between
`java.time` and `java.sql` date/time types and use the `java.sql` types at the JDBC boundary.

This change in behavior can have subtle impacts on legacy applications migrating to 8.0.
Set `hibernate.type.java_time_use_direct_jdbc` to `false` to retain the legacy behavior.
====

When `java.sql` date/time types are used (either in the model or by disabling
`hibernate.type.java_time_use_direct_jdbc`) it is important to make sure that
database server time zone agrees with JVM system time zone.  This is achieved using
the `hibernate.jdbc.time_zone` setting.

---

### Documentation Src Main Asciidoc Introduction Credits (`documentation/src/main/asciidoc/introduction/Credits.adoc`)

[[credits]]
== Credits

The full list of contributors to Hibernate ORM can be found on the
https://github.com/hibernate/hibernate-orm/graphs/contributors[GitHub repository].

The following contributors were involved in this documentation:

* Gavin King

---

### Documentation Src Main Asciidoc Introduction Entities (`documentation/src/main/asciidoc/introduction/Entities.adoc`)

[[entities]]
== Entities

An _entity_ is a Java class which represents data in a relational database table.
We say that the entity _maps_ or _maps to_ the table.
Much less commonly, an entity might aggregate data from multiple tables, but we'll get to that <<entity-table-mappings,later>>.

An entity has _attributes_—properties or fields—which map to columns of the table.
In particular, every entity must have an _identifier_ or _id_, which maps to the primary key of the table.
The id allows us to uniquely associate a row of the table with an instance of the Java class, at least within a given _persistence context_.

We'll explore the idea of a persistence context <<persistence-contexts,later>>. For now, think of it as a one-to-one mapping between ids and entity instances.

An instance of a Java class cannot outlive the virtual machine to which it belongs.
But we may think of an entity instance having a lifecycle which transcends a particular instantiation in memory.
By providing its id to Hibernate, we may re-materialize the instance in a new persistence context, as long as the associated row is present in the database.
Therefore, the operations `persist()` and `remove()` may be thought of as demarcating the beginning and end of the lifecycle of an entity, at least with respect to persistence.

Thus, an id represents the _persistent identity_ of an entity, an identity that outlives a particular instantiation in memory.
And this is an important difference between entity class itself and the values of its attributes—the entity has a persistent identity, and a well-defined lifecycle with respect to persistence, whereas a `String` or `List` representing one of its attribute values doesn't.

An entity usually has associations to other entities.
Typically, an association between two entities maps to a foreign key in one of the database tables.
A group of mutually associated entities is often called a _domain model_, though _data model_ is also a perfectly good term.

[[entity-clases]]
=== Entity classes

An entity must:

- be a non-`final` class,
- with a non-`private` constructor with no parameters.

On the other hand, the entity class may be either concrete or `abstract`, and it may have any number of additional constructors.

[TIP]
// .Inner entity classes
====
An entity class may be a `static` inner class.
====

[TIP]
====
These requirements are relaxed when the <<bytecode-enhancer,bytecode enhancer>> is used.
====

Every entity class must be annotated `@Entity`.

[source,java]
----
@Entity
class Book {
    Book() {}
    ...
}
----

Alternatively, the class may be identified as an entity type by providing an XML-based mapping for the class.

[TIP]
====
When XML-based mappings are used, the `<entity>` element is used to declare an entity class:

[source,xml]
----
<entity-mappings>
    <package>org.hibernate.example</package>

    <entity class="Book">
        <attributes> ... </attributes>
    </entity>

    ...
</entity-mappings>
----
Since the `orm.xml` mapping file format defined by the JPA specification was modelled closely on the annotation-based mappings, it's usually easy to go back and forth between the two options.
====

We won't have much more to say about XML-based mappings in this guide, since it's not our preferred way to do things.

.*Read more: "Dynamic" models*
[%collapsible]
====
****
:maps: {doc-user-guide-url}#dynamic-model
:envers: https://hibernate.org/orm/envers/
We love representing entities as classes because the classes give us a _type-safe_ model of our data.
But Hibernate also has the ability to represent entities as detyped instances of `java.util.Map`.
There's information in the {maps}[User Guide], if you're curious.

This must sound like a weird feature for a project that places importance on type-safety.
Actually, it's a useful capability for a very particular sort of generic code.
For example, the deprecated {envers}[Hibernate Envers] module is an auditing/versioning system for Hibernate entities.
Envers makes use of maps to represent its _versioned model_ of the data.
****
====

[[access-type]]
=== Access types

Each entity class has an _access type_, either:

- direct _field access_, or
- _property access_.

Hibernate automatically determines the access type from the location of attribute-level annotations.
Concretely:

- if a field is annotated `@Id`, field access is used, or
- if a getter method is annotated `@Id`, property access is used.

Back when Hibernate was just a baby, property access was quite popular in the Hibernate community.
Today, however, field access is _much_ more common.

[NOTE]
// .Explicit access type
====
The access type may be specified explicitly using the `@Access` annotation, but we strongly discourage this, since it's ugly and never necessary.
====

[IMPORTANT]
// .Mapping annotations should be placed consistently
====
Mapping annotations should be placed consistently:

- if `@Id` annotates a field, the other mapping annotations should also be applied to fields, or,
- if `@Id` annotates a getter, the other mapping annotations should be applied to getters.

It is in principle possible to mix field and property access using explicit `@Access` annotations at the attribute level.
We don't recommend doing this.
====

An entity class like `Book`, which does not extend any other entity class, is called a _root entity_.
Every root entity must declare an identifier attribute.

[[entity-inheritance]]
=== Entity class inheritance

An entity class may `extend` another entity class.

[source,java]
----
@Entity
class AudioBook extends Book {
    AudioBook() {}
    ...
}
----

A subclass entity inherits every persistent attribute of every entity it extends.

A root entity may also extend another class and inherit mapped attributes from the other class.
But in this case, the class which declares the mapped attributes must be annotated `@MappedSuperclass`.

[source,java]
----
@MappedSuperclass
class Versioned {
    ...
}

@Entity
class Book extends Versioned {
    ...
}
----

A root entity class must declare an attribute annotated `@Id`, or inherit one from a `@MappedSuperclass`.
A subclass entity always inherits the identifier attribute of the root entity.
It may not declare its own `@Id` attribute.

[[identifier-attributes]]
=== Identifier attributes

An identifier attribute is usually a field:

[source,java]
----
@Entity
class Book {
    Book() {}

    @Id
    Long id;
    
    ...
}
----

But it may be a property:

[source,java]
----
@Entity
class Book {
    Book() {}

    private Long id;
    
    @Id
    Long getId() { return id; }
    void setId(Long id) { this.id = id; }

    ...
}
----

An identifier attribute must be annotated `@Id` or `@EmbeddedId`.

Identifier values may be:

- assigned by the application, that is, by your Java code, or
- generated and assigned by Hibernate.

We'll discuss the second option first.

[[generated-identifiers]]
=== Generated identifiers

An identifier is often system-generated, in which case it should be annotated `@GeneratedValue`:

[source,java]
----
@Id @GeneratedValue
Long id;
----

[TIP]
// .Using surrogate keys
====
System-generated identifiers, or _surrogate keys_ make it easier to evolve or refactor the relational data model.
If you have the freedom to define the relational schema, we recommend the use of surrogate keys.
On the other hand, if, as is more common, you're working with a pre-existing database schema, you might not have the option.
====

JPA defines the following strategies for generating ids, which are enumerated by `GenerationType`:

.Standard id generation strategies
[%breakable,cols="25,15,~"]
|===
| Strategy                  | Java type | Implementation

| `GenerationType.UUID`     | `UUID` or `String`  | A Java `UUID`
| `GenerationType.IDENTITY` | `Long` or `Integer` | An identity or autoincrement column
| `GenerationType.SEQUENCE` | `Long` or `Integer` | A database sequence
| `GenerationType.TABLE`    | `Long` or `Integer` | A database table
| `GenerationType.AUTO`     | `Long` or `Integer` | Selects `SEQUENCE`, `TABLE`, or `UUID` based on the identifier type and capabilities of the database
|===

For example, this UUID is generated in Java code:

[source,java]
----
@Id @GeneratedValue UUID id;  // AUTO strategy selects UUID based on the field type
----

This id maps to a SQL `identity`, `auto_increment`, or `bigserial` column:

[source,java]
----
@Id @GeneratedValue(strategy = IDENTITY) Long id;
----

The `@SequenceGenerator` and `@TableGenerator` annotations allow further control over `SEQUENCE` and `TABLE` generation respectively.

Consider this sequence generator:

[source,java]
----
@SequenceGenerator(name = "bookSeq", sequenceName = "seq_book", initialValue = 5, allocationSize=10)
----

Values are generated using a database sequence defined as follows:

[source,sql]
----
create sequence seq_book start with 5 increment by 10
----

Notice that Hibernate doesn't have to go to the database every time a new identifier is needed.
Instead, a given process obtains a block of ids, of size `allocationSize`, and only needs to hit the database each time the block is exhausted.
Of course, the downside is that generated identifiers are not contiguous.

[CAUTION]
// .Check the `initialValue` and `allocationSize`
====
If you let Hibernate export your database schema, the sequence definition will have the right `start with` and `increment` values.
But if you're working with a database schema managed outside Hibernate, make sure the `initialValue` and `allocationSize` members of `@SequenceGenerator` match the `start with` and `increment` specified in the DDL.
====

Any identifier attribute may now make use of the generator named `bookSeq`:

[source,java]
----
@Id
@GeneratedValue(generator = "bookSeq")  // reference to generator defined elsewhere
Long id;
----

Actually, it's extremely common to place the `@SequenceGenerator` annotation on the `@Id` attribute that makes use of it:

[source,java]
----
@Id
@GeneratedValue  // uses the generator defined below
@SequenceGenerator(sequenceName = "seq_book", initialValue = 5, allocationSize=10)
Long id;
----

In this case, the `name` of the `@SequenceGenerator` should not be specified.

We may even place a `@SequenceGenerator` or `@TableGenerator` annotation at the package level:

[source,java]
----
@SequenceGenerator(sequenceName = "id_sequence", initialValue = 5, allocationSize=10)
@TableGenerator(table = "id_table", initialValue = 5, allocationSize=10)
package org.example.entities;
----

Then any entity in this package which specifies `strategy=SEQUENCE` or `strategy=TABLE` without also explicitly specifying a generator `name` is assigned a generator based on the package-level annotation.

[source,java]
----
@Id
@GeneratedValue(strategy=SEQUENCE)  // uses the sequence generator defined at the package level
Long id;
----

// [NOTE]
// // .JPA id generators may be shared between entities
// ====
// JPA id generators may be shared between entities.
// A `@SequenceGenerator` or `@TableGenerator` must have a name, and may be shared between multiple id attributes.
// This fits somewhat uncomfortably with the common practice of annotating the `@Id` attribute which makes use of the generator!
// ====

As you can see, JPA provides quite adequate support for the most common strategies for system-generated ids.
However, the annotations themselves are a bit more intrusive than they should be, and there's no well-defined way to extend this framework to support custom strategies for id generation.
Nor may `@GeneratedValue` be used on a property not annotated `@Id`.
Since custom id generation is a rather common requirement, Hibernate provides a very carefully-designed framework for user-defined ``Generator``s, which we'll discuss in <<user-defined-generators>>.

[[natural-identifiers]]
=== Natural keys as identifiers

Not every identifier attribute maps to a (system-generated) surrogate key.
Primary keys which are meaningful to the user of the system are called _natural keys_.

When the primary key of a table is a natural key, we don't annotate the identifier attribute `@GeneratedValue`, and it's the responsibility of the application code to assign a value to the identifier attribute.

[source,java]
----
@Entity
class Book {
    @Id
    String isbn;

    ...
}
----

Of particular interest are natural keys which comprise more than one database column, and such natural keys are called _composite keys_.

[[composite-identifiers]]
=== Composite identifiers

If your database uses composite keys, you'll need more than one identifier attribute.
There are two ways to map composite keys in JPA:

- using an `@IdClass`, or
- using an `@EmbeddedId`.

Perhaps the most immediately-natural way to represent this in an entity class is with multiple fields annotated `@Id`, for example:

[source,java]
----
@Entity
@IdClass(BookId.class)
class Book {
    Book() {}

    @Id
    String isbn;

    @Id
    int printing;

    ...
}
----

But this approach comes with a problem: what object can we use to identify a `Book` and pass to methods like `find()` which accept an identifier?

The solution is to write a separate class with fields that match the identifier attributes of the entity.
Every such id class must override `equals()` and `hashCode()`.
Of course, the easiest way to satisfy these requirements is to declare the id class as a `record`.

[source,java]
----
record BookId(String isbn, int printing) {}
----

The `@IdClass` annotation of the `Book` entity identifies `BookId` as the id class to use for that entity.

This is not our preferred approach.
Instead, we recommend that the `BookId` class be declared as an `@Embeddable` type:

[source,java]
----
@Embeddable
record BookId(String isbn, int printing) {}
----

We'll learn more about <<embeddable-objects>> below.

Now the entity class may reuse this definition using `@EmbeddedId`, and the `@IdClass` annotation is no longer required:

[source,java]
----
@Entity
class Book {
    Book() {}

    @EmbeddedId
    BookId bookId;

    ...
}
----

This second approach eliminates some duplicated code.

Either way, we may now use `BookId` to obtain instances of `Book`:

[source,java]
----
Book book = session.find(Book.class, new BookId(isbn, printing));
----

[[version-attributes]]
=== Version attributes

An entity may have an attribute which is used by Hibernate for <<optimistic-and-pessimistic-locking,optimistic lock verification>>.
A _version attribute_ is usually of type `Integer`, `Short`, `Long`, `LocalDateTime`, `OffsetDateTime`, `ZonedDateTime`, or `Instant`.

[source,java]
----
@Version
int version;
----

[source,java]
----
@Version
LocalDateTime lastUpdated;
----

A version attribute is automatically assigned by Hibernate when an entity is made persistent, and automatically incremented or updated each time the entity is updated.

If the version attribute is numeric, then an entity is, by default, assigned the version number `0` when it's first made persistent.
It's easy to specify that the initial version should be assigned the number `1` instead:

[source,java]
----
@Version
int version = 1; // the initial version number
----

If the version attribute is an `Instant` or datetime, the value assigned to the attribute is generated in the JVM by default.

[TIP]
====
If the datetime value should be generated by the database, the `@Version` annotation may be used in conjunction with a <<user-defined-generators,generator annotation>>, for example:
[source,java]
----
@CurrentTimestamp @Version
LocalDateTime lastUpdated;
----
====

Almost every entity which is frequently updated should have a version attribute.

The `@ExcludedFromVersioning` annotation lets us selectively exclude a certain field from optimistic locking, so that modifications to the annotated field do not result in a version increment.

[TIP]
// .Optimistic locking in Hibernate
====
If an entity doesn't have a version number, which often happens when mapping legacy data, we can still do optimistic locking.
The link:{doc-javadoc-url}org/hibernate/annotations/OptimisticLocking.html[`@OptimisticLocking`] annotation lets us specify that optimistic locks should be checked by validating the values of `ALL` fields, or only the `DIRTY` fields of the entity.
And the `@ExcludedFromVersioning` annotation lets us selectively exclude certain fields from validation.
====

The `@Id` and `@Version` attributes we've already seen are just specialized examples of _basic attributes_.

[[natural-id-attributes]]
=== Natural id attributes

Even when an entity has a surrogate key, it should always be possible to write down a combination of fields which uniquely identifies an instance of the entity, from the point of view of the user of the system.
This combination of fields is its natural key.
Above, we <<natural-identifiers,considered>> the case where the natural key coincides with the primary key.
Here, the natural key is a second unique key of the entity, distinct from its surrogate primary key.

[IMPORTANT]
// .What if my entity has no natural key?
====
If you can't identify a natural key, it might be a sign that you need to think more carefully about some aspect of your data model.
If an entity doesn't have a meaningful unique key, then it's impossible to say what event or object it represents in the "real world" outside your program.
====

Since it's _extremely_ common to retrieve an entity based on its natural key, Hibernate has a way to mark the attributes of the entity which make up its natural key.
Each attribute must be annotated link:{doc-javadoc-url}org/hibernate/annotations/NaturalId.html[`@NaturalId`].

[source,java]
----
@Entity
class Book {
    Book() {}

    @Id @GeneratedValue
    Long id; // the system-generated surrogate key

    @NaturalId
    String isbn; // belongs to the natural key

    @NaturalId
    int printing; // also belongs to the natural key

    ...
}
----

Hibernate automatically generates a `UNIQUE` constraint on the columns mapped by the annotated fields.

[TIP]
====
Consider using the natural id attributes to implement <<equals-and-hash>>.
====

If the natural id is a composite key spanning multiple attributes, a link:{doc-javadoc-url}org/hibernate/annotations/NaturalIdClass.html[`@NaturalIdClass`] may be used.
This is very similar to the `@IdClass` annotation we <<composite-identifiers,already met>>.

[source,java]
----
record BookKey(String isbn, int printing) {}

@Entity
@NaturalIdClass(BookKey.class)
class Book {
    ...
}
----

The payoff for doing this extra work, as we will see <<natural-id-cache,much later>>, is that we can take advantage of optimized natural id lookups that make use of the second-level cache.

Note that even when you've identified a natural key, we still recommend the use of a generated surrogate key in foreign keys, since this makes your data model _much_ easier to change.

[[basic-attributes]]
=== Basic attributes

A _basic_ attribute of an entity is a field or property which maps to a single column of the associated database table.
The JPA specification defines a quite limited set of basic types:

[[basic-type-list]]
.JPA-standard basic attribute types
[%breakable,cols="30,^14,~"]
|====
| Classification | Package | Types

| Primitive types | | `boolean`, `int`, `double`, etc
| Primitive wrappers | `java.lang` | `Boolean`, `Integer`, `Double`, etc
| Strings | `java.lang` | `String`
| Arbitrary-precision numeric types | `java.math` | `BigInteger`, `BigDecimal`
| UUIDs | `java.util` | `UUID`
| Date/time types | `java.time` | `LocalDate`, `LocalTime`, `LocalDateTime`, `OffsetDateTime`, `Instant`, `Year`
| Deprecated date/time types 💀 | `java.util` | `Date`, `Calendar`
| Deprecated JDBC date/time types 💀 | `java.sql` | `Date`, `Time`, `Timestamp`
| Binary and character arrays | | `byte[]`, `char[]`
| Binary and character wrapper arrays 💀 | `java.lang` | `Byte[]`, `Character[]`
| Enumerated types | | Any `enum`
| Serializable types | | Any type which implements `java.io.Serializable`
|====

[IMPORTANT]
// .Please don't use `Date`!
====
We're begging you to use types from the `java.time` package instead of anything which inherits `java.util.Date`.
====

[WARNING]
====
The use of `Byte[]` and `Character[]` as basic types was deprecated by Jakarta Persistence 3.2.
Hibernate does not allow `null` elements in such arrays.
Use `byte[]` or `char[]` instead.
====

[CAUTION]
// .Serialization is usually a bad idea
====
Serializing a Java object and storing its binary representation in the database is usually wrong.
As we'll soon see in <<embeddable-objects>>, Hibernate has much better ways to handle complex Java objects.
====

Hibernate slightly extends this list with the following types:

.Additional basic attribute types in Hibernate
[%breakable,cols="30,^14,56"]
|====
| Classification | Package | Types

| Additional date/time types | `java.time` | `Duration`, `ZoneId`, `ZoneOffset`, and even `ZonedDateTime`
| JDBC LOB types | `java.sql` | `Blob`, `Clob`, `NClob`
| Java class object | `java.lang` | `Class`
| Internet addresses | `java.net` | `InetAddress`
| Miscellaneous types | `java.util` | `Currency`, `Locale`, `URL`, `TimeZone`
|====

The `@Basic` annotation explicitly specifies that an attribute is basic, but it's often not needed, since attributes are assumed basic by default.
On the other hand, if a non-primitively-typed attribute cannot be null, use of `@Basic(optional=false)` is highly recommended.

[source,java]
----
@Basic(optional=false) String firstName;
@Basic(optional=false) String lastName;
String middleName; // may be null
----

Alternatively, use the Jakarta `@Nonnull` annotation.

[source,java]
----
@Nonnull String firstName;
@Nonnull String lastName;
String middleName; // may be null
----

Note that primitively-typed attributes are inferred `NOT NULL` by default.

.*Read more: Not-null columns*
[%collapsible]
====
****
Until JPA 4, there were two standard ways to add a `NOT NULL` constraint to a mapped column in JPA:

1. using `@Basic(optional=false)`, or
2. using `@Column(nullable=false)`.

You might wonder what the difference is.

Well, it's perhaps not obvious to a casual user of the JPA annotations, but they actually come in two "layers":

- annotations like `@Entity`, `@Id`, and `@Basic` belong to the _logical_ layer, the subject of the current chapter—they specify the semantics of your Java domain model, whereas
- annotations like `@Table` and `@Column` belong to the _mapping_ layer, the topic of the <<object-relational-mapping,next chapter>>—they specify how elements of the domain model map to objects in the relational database.

Information may be inferred from the logical layer down to the mapping layer, but is never inferred in the opposite direction.

Now, the `@Column` annotation, to whom we'll be properly <<regular-column-mappings,introduced>> a bit later, belongs to the _mapping_ layer, and so its `nullable` member only affects schema generation (resulting in a `not null` constraint in the generated DDL).
On the other hand, the `@Basic` annotation belongs to the logical layer, and so an attribute marked `optional=false` is checked by Hibernate before it even writes an entity to the database.
Note that:

- `optional=false` implies `nullable=false`, but
- `nullable=false` _does not_ imply `optional=false`.

Therefore, we prefer `@Basic(optional=false)` to `@Column(nullable=false)`.

But wait!
JPA 4 provides two additional options:

1. Use `@Nonnull` from `jakarta.annotation`, or
2. use the `@NotNull` constraint from Bean Validation.footnote:[You'll need to add Hibernate Validator to your project build, as described in <<optional-dependencies>>.]

We think that these are easier on the eyes.
****
====

[[enums]]
=== Enumerated types

We included Java ``enum``s on the list above.
An enumerated type is considered a sort of basic type, but since most databases don't have a native `ENUM` type, JPA provides a special `@Enumerated` annotation to specify how the enumerated values should be represented in the database:

- by default, an enum is stored as an integer, the value of its `ordinal()` member, but
- if the attribute is annotated `@Enumerated(STRING)`, it is stored as a string, the value of its `name()` member.

[source,java]
----
//here, an ORDINAL encoding makes sense
@Enumerated
@Basic(optional=false)
DayOfWeek dayOfWeek;

//but usually, a STRING encoding is better
@Enumerated(EnumType.STRING)
@Basic(optional=false)
Status status;

----

The `@EnumeratedValue` annotation allows the column value to be customized:

[source,java]
----
enum Resolution {
    UNRESOLVED(0), FIXED(1), REJECTED(-1);

    @EnumeratedValue // store the code, not the enum ordinal() value
    final int code;

    Resolution(int code) {
         this.code = code;
    }
}
----

Since Hibernate 6, an `enum` annotated `@Enumerated(STRING)` is mapped to:

- a `VARCHAR` column type with a `CHECK` constraint on most databases, or
- an `ENUM` column type on MySQL.

Any other ``enum`` is mapped to a `TINYINT` column with a `CHECK` constraint.

[TIP]
// .It's usually better to persist `enum` values by their names
====
JPA picks the wrong default here.
In most cases, storing an integer encoding of the `enum` value makes the relational data harder to interpret.

Even considering `DayOfWeek`, the encoding to integers is ambiguous.
If you check `java.time.DayOfWeek`, you'll notice that `SUNDAY` is encoded as `6`.
But in the country I was born, `SUNDAY` is the _first_ day of the week!

So we prefer `@Enumerated(STRING)` for most `enum` attributes.
====

An interesting special case arises on PostgreSQL and Oracle.

[[named-enums]]
[TIP]
====
Some databases support _named_ `ENUM` types, which must be declared using in DDL using:

- `CREATE TYPE ... AS ENUM` on PostgreSQL, or
- `CREATE DOMAIN ... AS ENUM` on Oracle.

These look like a perfect match for Java ``enum``s, which also have names!

Sadly, these `ENUM` types aren't well-integrated with the SQL language, nor well-supported by the JDBC drivers, so Hibernate doesn't use them by default.
But if you would like to use a named enumerated type on Postgres or Oracle, just annotate your `enum` attribute like this:

[source,java]
----
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
@Basic(optional=false)
Status status;
----

Alternatively, you may enable the configuration property link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#PREFER_NATIVE_ENUM_TYPES[`hibernate.type.prefer_native_enum_types`].
====

The limited set of pre-defined basic attribute types can be stretched a bit further by supplying a _converter_.

[[converters]]
=== Converters

A JPA `AttributeConverter` is responsible for:

- converting a given Java type to one of the types listed above, and/or
- perform any other sort of pre- and post-processing you might need to perform on a basic attribute value before writing and reading it to or from the database.

Converters substantially widen the set of attribute types that can be handled by JPA.

There are two ways to apply a converter:

- the `@Convert` annotation applies an `AttributeConverter` to a particular entity attribute, or
- the `@Converter` annotation (or, alternatively, the `@ConverterRegistration` annotation) registers an `AttributeConverter` for automatic application to all attributes of a given type.
  `@ConverterRegistration` should preferably be placed on a `package-info.java` or `module-info.java`.

For example, the following converter is automatically applied to any attribute of type `EnumSet<DayOfWeek>`, and takes care of persisting the `EnumSet<DayOfWeek>` to a column of type `INTEGER`:

[source,java]
----
@Converter(autoApply = true)
public static class EnumSetConverter
        // converts Java values of type EnumSet<DayOfWeek> to integers for storage in an INT column
        implements AttributeConverter<EnumSet<DayOfWeek>,Integer> {
    @Override
    public Integer convertToDatabaseColumn(EnumSet<DayOfWeek> enumSet) {
        int encoded = 0;
        var values = DayOfWeek.values();
        for (int i = 0; i<values.length; i++) {
            if (enumSet.contains(values[i])) {
                encoded |= 1<<i;
            }
        }
        return encoded;
    }

    @Override
    public EnumSet<DayOfWeek> convertToEntityAttribute(Integer encoded) {
        var set = EnumSet.noneOf(DayOfWeek.class);
        var values = DayOfWeek.values();
        for (int i = 0; i<values.length; i++) {
            if (((1<<i) & encoded) != 0) {
                set.add(values[i]);
            }
        }
        return set;
    }
}
----

On the other hand, if we _don't_ set `autoapply=true`, then we must explicitly apply the converter using the `@Convert` annotation:

[source,java]
----
@Convert(converter = EnumSetConverter.class)
@Basic(optional = false)
EnumSet<DayOfWeek> daysOfWeek;
----

[CAUTION]
====
Converters are supposed to be used for type conversion.
Some enterprising members of the community have noticed that they can be (mis)used to perform other tasks: trimming whitespace, normalizing case, assigning a default value in place of `null`, and so on.
Hibernate _tolerates_ but does not encourage such (mis)use.
In particular, we strongly recommend against defining an `autoApply` converter acting on a <<basic-type-list,basic type>>.
====

All this is nice, but it probably won't surprise you that Hibernate goes beyond what is required by JPA.

[[compositional-basic-types]]
=== Compositional basic types

Hibernate considers a "basic type" to be formed by the marriage of two objects:

- a `JavaType`, which models the semantics of a certain Java class, and
- a `JdbcType`, representing a SQL type which is understood by JDBC.

When mapping a basic attribute, we may explicitly specify a `JavaType`, a `JdbcType`, or both.

[[java-type]]
[discrete]
==== JavaType

An instance of `org.hibernate.type.descriptor.java.JavaType` represents a particular Java class.
It's able to:

- compare instances of the class to determine if an attribute of that class type is dirty (modified),
- produce a useful hash code for an instance of the class,
- coerce values to other types, and, in particular,
- convert an instance of the class to one of several other equivalent Java representations at the request of its partner `JdbcType`.

For example, `IntegerJavaType` knows how to convert an `Integer` or `int` value to the types `Long`, `BigInteger`, and `String`, among others.

We may explicitly specify a Java type using the `@JavaType` annotation, but for the built-in ``JavaType``s this is never necessary.

[source,java]
----
@JavaType(LongJavaType.class)  // not needed, this is the default JavaType for long
long currentTimeMillis;
----

For a user-written `JavaType`, the annotation is more useful:

[source,java]
----
@JavaType(BitSetJavaType.class)
BitSet bitSet;
----

Alternatively, the `@JavaTypeRegistration` annotation may be used to register `BitSetJavaType` as the default `JavaType` for `BitSet`.
This annotation should preferably be placed on a `package-info.java` or `module-info.java`.

[[jdbc-type]]
[discrete]
==== JdbcType

An `org.hibernate.type.descriptor.jdbc.JdbcType` is able to read and write a single Java type from and to JDBC.

For example, `VarcharJdbcType` takes care of:

- writing Java strings to JDBC ``PreparedStatement``s by calling `setString()`, and
- reading Java strings from JDBC ``ResultSet``s using `getString()`.

By pairing `LongJavaType` with `VarcharJdbcType` in holy matrimony, we produce a basic type which maps ``Long``s and primitive ``longs``s to the SQL type `VARCHAR`.

We may explicitly specify a JDBC type using the `@JdbcType` annotation.

[source,java]
----
@JdbcType(VarcharJdbcType.class)
long currentTimeMillis;
----

Alternatively, we may specify a JDBC type code:

[source,java]
----
@JdbcTypeCode(Types.VARCHAR)
long currentTimeMillis;
----

The `@JdbcTypeRegistration` annotation may be used to register a user-written `JdbcType` as the default for a given SQL type code.
This annotation should preferably be placed on a `package-info.java` or `module-info.java`.

[NOTE]
====
The types defined by the JDBC specification are enumerated by the integer type codes in the class `java.sql.Types`.
Each JDBC type is an abstraction of a commonly-available type in SQL.
For example, `Types.VARCHAR` represents the SQL type `VARCHAR` (or `VARCHAR2` on Oracle).

Since Hibernate understands more SQL types than JDBC, there's an extended list of integer type codes in the class link:{doc-javadoc-url}org/hibernate/type/SqlTypes.html[`org.hibernate.type.SqlTypes`].
For example, `SqlTypes.GEOMETRY` represents the spatial data type `GEOMETRY`.
====

[discrete]
==== AttributeConverter

If a given `JavaType` doesn't know how to convert its instances to the type required by its partner `JdbcType`, we must help it out by providing a JPA `AttributeConverter` to perform the conversion.

For example, to form a basic type using `LongJavaType` and `TimestampJdbcType`, we would provide an `AttributeConverter<Long,Timestamp>`.

[source,java]
----
@JdbcType(TimestampJdbcType.class)
@Convert(converter = LongToTimestampConverter.class)
long currentTimeMillis;
----

Let's abandon our analogy right here, before we start calling this basic type a "throuple".

[[datetime-types]]
=== Date and time types, and time zones

Dates and times should always be represented using the types defined in `java.time`.

[WARNING]
====
Never use the legacy types `java.sql.Date`, `java.sql.Time`, `java.sql.Timestamp`, or `java.util.Date`.
At our urging, support for these types has even been https://in.relation.to/2024/04/22/stop-using-date/[officially deprecated in JPA 3.2].
Eventually, we hope to completely remove support for these types from the JPA spec and from Hibernate.
====

Some of the types in `java.time` map naturally to an ANSI SQL column type.
A source of confusion is that some databases still don't follow the ANSI standard naming here.
Also, as you're probably aware, the `DATE` type on Oracle is not an ANSI SQL `DATE`.
In fact, Oracle doesn't have `DATE` or `TIME` types--every date or time must be stored as a timestamp.

.Type mappings from `java.time` to ANSI SQL
|====
| `java.time` class | ANSI SQL type | MySQL | SQL Server | Oracle

| `LocalDate` | `DATE` | `DATE` | `DATE` | `DATE` 💀
| `LocalTime` | `TIME` | `TIME` | `TIME` | `TIMESTAMP` 💀
| `LocalDateTime` | `TIMSTAMP` | `DATETIME` | `DATETIME2` | `TIMESTAMP`
| `OffsetDateTime`, `ZonedDateTime` | `TIMESTAMP WITH TIME ZONE` | `TIMESTAMP` 🙄 | `DATETIMEOFFSET` | `TIMESTAMP WITH TIME ZONE`
|====

On the other hand, there are no perfectly natural mappings for `Instant` and `Duration` on most databases.
By default:

- `Duration` is mapped to a column of type `NUMERIC(21)` holding the length of the duration in nanoseconds, and
- `Instant` is mapped to a column of type `TIMESTAMP` (`DATETIME` on MySQL) or TIMESTAMP WITH TIME ZONE, depending on the database.

Fortunately, these mappings can be modified by specifying the `JdbcType`.

For example, if we wanted to store an `Instant` using `TIMESTAMP WITH TIME ZONE` (`TIMESTAMP` on MySQL) instead of `TIMESTAMP`, then we could annotate the field:

[source,java]
----
// store the Instant as a TIMESTAMP WITH TIME ZONE, instead of as a TIMESTAMP
@JdbcTypeCode(SqlTypes.TIMESTAMP_WITH_TIMEZONE)
Instant instant;
----

Alternatively, we could set the configuration property `hibernate.type.preferred_instant_jdbc_type`:


[source,java]
----
// store field of type Instant as TIMESTAMP WITH TIME ZONE, instead of as a TIMESTAMP
config.setProperty(MappingSettings.PREFERRED_INSTANT_JDBC_TYPE, SqlTypes.TIMESTAMP_WITH_TIMEZONE);
----

We have worked very hard to make sure that Java date and time types work with consistent and correct semantics across all databases supported by Hibernate.
In particular, Hibernate is very careful in how it handles time zones.

[WARNING]
====
Unfortunately, with the notable exception of Oracle, most SQL databases feature embarrassingly poor support for timezones.
Even some databases which do supposedly support `TIMESTAMP WITH TIME ZONE` simply covert the datetime to UTC.
Here, Hibernate is limited by the capabilities of the databases themselves, and so on many databases, time zone information will not, by default, be preserved for an `OffsetDateTime` or `ZonedDateTime`.
====

[TIP]
====
The still-experimental annotation link:{doc-javadoc-url}org/hibernate/annotations/TimeZoneStorage.html[`@TimeZoneStorage`] provides some additional options in case the default behavior falls short.
//
// [source,java]
// ----
// @TimeZoneStorage(COLUMN)
// @TimeZoneColumn(name = "event_offset")
// @Column(name = "event_timestamp")
// private OffsetDateTime eventDateTime;
// ----
====

[[embeddable-objects]]
=== Embeddable objects

An embeddable object is a Java class whose state maps to multiple columns of a table, but which doesn't have its own persistent identity.
That is, it's a class with mapped attributes, but no `@Id` attribute.

An embeddable object can only be made persistent by assigning it to the attribute of an entity.
Since the embeddable object does not have its own persistent identity, its lifecycle with respect to persistence is completely determined by the lifecycle of the entity to which it belongs.

An embeddable class must be annotated `@Embeddable` instead of `@Entity`.

[source,java]
----
@Embeddable
class Name {
    
    @Basic(optional=false)
    String firstName;

    @Basic(optional=false)
    String lastName;
    
    String middleName;
    
    Name() {}

    Name(String firstName, String middleName, String lastName) {
        this.firstName = firstName;
        this.middleName = middleName;
        this.lastName = lastName;
    }
    
    ...
}
----

An embeddable class must satisfy the same requirements that entity classes satisfy, with the exception that an embeddable class has no `@Id` attribute.
In particular, it must have a constructor with no parameters.

Alternatively, an embeddable type may be defined as a Java record type:

[source,java]
----
@Embeddable
record Name(String firstName, String middleName, String lastName) {}
----

In this case, the requirement for a constructor with no parameters is relaxed.

We may now use our `Name` class (or record) as the type of an entity attribute:

[source,java]
----
@Entity
class Author {
    @Id @GeneratedValue
    Long id;
    
    Name name;
    
    ...
}
----

Embeddable types can be nested.
That is, an `@Embeddable` class may have an attribute whose type is itself a different `@Embeddable` class.

[TIP]
// .The `@Embedded` annotation is not required
====
JPA provides an `@Embedded` annotation to identify an attribute of an entity that refers to an embeddable type.
This annotation is completely optional, and so we don't usually use it.
====

Usually, embeddable types are stored in a "flattened" format.
Their attributes map columns of the table of their parent entity.
Later, in <<mapping-embeddables>>, we'll see a couple of different options.

An attribute of embeddable type represents a relationship between a Java object with a persistent identity, and a Java object with no persistent identity.
We can think of it as a whole/part relationship.
The embeddable object belongs to the entity, and can't be shared with other entity instances.
And it exists for only as long as its parent entity exists.

Since Hibernate 6.6, an embedded attribute whose declared type is an embeddable class with embeddable subclasses is fully polymorphic.

Next we'll discuss a different kind of relationship: a relationship between Java objects which each have their own distinct persistent identity and persistence lifecycle.

[[associations]]
=== Associations

An _association_ is a relationship between entities.
We usually classify associations based on their _multiplicity_.
If `R` and `F` are both entity classes, then:

- a _one-to-one_ association relates at most one unique instance `R` with at most one unique instance of `F`,
- a _many-to-one_ association relates zero or more instances of `R` with a unique instance of `F`, and
- a _many-to-many_ association relates zero or more instances of `R` with zero or more instance of `F`.

An association between entity classes may be either:

- _unidirectional_, navigable from `R` to `F` but not from `F` to `R`, or
- _bidirectional_, and navigable in either direction.

In this example data model, we can see the sorts of associations which are possible:

image::images/associations.png[Example data model,align="center",pdfwidth=90%]

[%unbreakable]
[TIP]
// .One-to-one associations and subtyping
====
An astute observer of the diagram above might notice that the relationship we've presented as a unidirectional one-to-one association could reasonably be represented in Java using subtyping.
This is quite normal.
A one-to-one association is the usual way we implement subtyping in a fully-normalized relational model.
It's related to the `JOINED` <<mapping-inheritance,inheritance mapping>> strategy.
====

There are three annotations for mapping associations: `@ManyToOne`, `@OneToMany`, and `@ManyToMany`.
They share some common annotation members:

.Association-defining annotation members
[%breakable,cols="13,~,35"]
|===
| Member | Interpretation | Default value

| `cascade` | Persistence operations which should <<cascade,cascade>> to the associated entity; a list of ``CascadeType``s | `{}`
| `fetch` | Whether the association is <<entity-graph,eagerly>> <<association-fetching,fetched>> or may be <<proxies-and-lazy-fetching,proxied>>
a|
- `LAZY` for `@OneToMany` and `@ManyToMany`
- `EAGER` for `@ManyToOne` 💀💀💀
| `targetEntity` | The associated entity class | Determined from the attribute type declaration
| `optional` | For a `@ManyToOne` or `@OneToOne` association, whether the association can be `null` | `true`
| `mappedBy` | For a bidirectional association, an attribute of the associated entity which maps the association | By default, the association is assumed unidirectional
|===

We'll explain the effect of these members as we consider the various types of association mapping.

It's not a requirement to represent _every_ foreign key relationship as an association at the Java level.
It's perfectly acceptable to replace a `@ManyToOne` mapping with a basic-typed attribute holding an identifier, if it's inconvenient to think of this relationship as an association at the Java level.
That said, it's possible to take this idea way too far.


.*Read more: 💀 Aggregates 💀*
[%collapsible]
====
****
It's come to our attention that a vocal group of people advocate that Java entity classes should be broken up into tiny disconnected islands they call "aggregates". An aggregate--at least as a first approximation--corresponds roughly to what we would usually call a parent/child relationship.
Simple examples of aggregates might be `Order`/`Item`, or `Product`/`Part`.
According to this way of thinking, there should be no associations _between_ aggregates.
So the `Item.product` association should be replaced with `productId`, `Part.manufacturer` should be replaced with `manufacturerId`, and so on.
(Of course, the word "aggregate" may also be employed in other senses, but this is the sense we're discussing right now.)

In the example we've been using, `Book` would not be permitted to have a collection of entity type `Author`, and should instead hold only the ids of the authors, or perhaps instances of some `BookAuthor` type which duplicates some state of `Author` and is disconnected from the rest of the model.

Let's stipulate that this might be a perfectly natural thing to do in certain contexts, for example, when accessing a document database.
But one context where it doesn't usually make sense is when accessing a relational database via Hibernate.
The reason is that Hibernate offers <<association-fetching,rich functionality>> for optimizing access to associated data, including:

- the <<second-level-cache,second level cache>>, and
- join, batch, and subselect fetching, whether via HQL, <<entity-graph,entity graphs>>, or <<fetch-profiles,fetch profiles>>.

But all this functionality is lost if Hibernate doesn't know it's dealing with an association, inevitably making the application program much more vulnerable to problems with <<association-fetching,N+1 selects>>, just as soon as we encounter a business requirement which involves data from more than one aggregate.
(Always keep in mind that business requirements change much faster than relational data models!)

To put it mildly: this is not how JPA was ever intended to be used.

It's difficult to respond charitably to most of the arguments in favor of this approach, since most of them don't rise above the level of hand-waving at boxes on drawn on whiteboards.
An argument we _can_ respond to is the concern that transparent lazy fetching can lead to "accidental" fetching of an association and the potential for N+1 selects.
This is a legit concern, and one we worry about too, but where it's really a problem we have a much better solution: just use a `EntityAgent`, or a stateless Jakarta Data repository, where <<stateless-sessions,association fetching is always an explicit operation>>.
Indeed, `EntityAgent` even guards against accidental _updates_, since `update()` is always an explicit operation.
****
====

Now that we know that associations are actually good and useful, let's see how to model the various kinds of association we might find need to map to a relational data model.
We begin with the most common association multiplicity.

[[many-to-one]]
=== Many-to-one

A many-to-one association is the most basic sort of association we can imagine.
It maps completely naturally to a foreign key in the database.
Almost all the associations in your domain model are going to be of this form.

[TIP]
// .One-to-many join table mappings
====
Later, we'll see how to map a many-to-one association to an <<join-table-mappings,association table>>.
====

The `@ManyToOne` annotation marks the "to one" side of the association, so a unidirectional many-to-one association looks like this:

[source,java]
----
class Book {
    @Id @GeneratedValue
    Long id;

    @ManyToOne(fetch=LAZY)
    Publisher publisher;

    ...
}
----

Here, the `Book` table has a foreign key column holding the identifier of the associated `Publisher`.

[[lazy-problem]]
[WARNING]
// .Almost all associations should be lazy
====
A very unfortunate misfeature of JPA is that `@ManyToOne` associations are fetched eagerly by default.
This is almost never what we want.
Almost all associations should be lazy.
The only scenario in which `fetch=EAGER` makes sense is if we think there's always a _very_ high probability that the <<caching-and-fetching,associated object will be found in the second-level cache>>.
Whenever this isn't the case, remember to explicitly specify `fetch=LAZY`.
Or, even better, configure Hibernate with a `LAZY` default fetch mode for to-one associations using `<default-to-one-fetch-type>` or `defaultToOneFetchType()`.
====

Most of the time, we would like to be able to easily navigate our associations in both directions.
We do need a way to get the `Publisher` of a given `Book`, but we would also like to be able to obtain all the ``Book``s belonging to a given publisher.

To make this association bidirectional, we need to add a collection-valued attribute to the `Publisher` class, and annotate it `@OneToMany`.

[NOTE]
====
Hibernate needs to <<proxies-and-lazy-fetching,proxy>> unfetched associations at runtime.
Therefore, the many-valued side must be declared using an interface type like `Set` or `List`, and never using a concrete type like `HashSet` or `ArrayList`.
====

To indicate clearly that this is a bidirectional association, and to reuse any mapping information already specified in the `Book` entity, we must use the `mappedBy` annotation member to refer back to `Book.publisher`.

[source,java]
----
@Entity
class Publisher {
    @Id @GeneratedValue
    Long id;

    @OneToMany(mappedBy="publisher")
    Set<Book> books;

    ...
}
----

The `Publisher.books` field is called the _unowned_ side of the association.

Now, we passionately _hate_ the stringly-typed `mappedBy` reference to the owning side of the association.
Thankfully, the <<metamodel-generator, Hibernate Processor>> gives us a way to make it a
bit more type safe:

[[mapped-by-metamodel]]
[source,java]
----
@OneToMany(mappedBy=Book_.PUBLISHER)  // get used to doing it this way!
Set<Book> books;
----
We're going to use this approach for the rest of the Short Guide.

To modify a bidirectional association, we must change the _owning side_.

[[bidirectional-problem]]
[WARNING]
// .To modify a bidirectional association, you must change the _owning side_!
====
Changes made to the unowned side of an association are never synchronized to the database.
If we desire to change an association in the database, we must change it from the owning side.
Here, we must set `Book.publisher`.

In fact, it's often necessary to change _both sides_ of a bidirectional association.
For example, if the collection `Publisher.books` was stored in the second-level cache, we must also modify the collection, to ensure that the second-level cache remains synchronized with the database.
====

That said, it's _not_ a hard requirement to update the unowned side, at least if you're sure you know what you're doing.

Here we've used `Set` as the type of the collection, but Hibernate also allows the use of `List` or `Collection` here, with almost no difference in semantics.
In particular, the `List` may not contain duplicate elements, and its order will not be persistent.

[source,java]
----
@OneToMany(mappedBy=Book_.PUBLISHER)
Collection<Book> books;
----

We'll see how to map a collection with a persistent order <<ordered-sorted,much later>>.

[[set-vs-list]]
.*Read more: Set, List, or Collection?*
[%collapsible]
====
****
A one-to-many association mapped to a foreign key can never contain duplicate elements, so `Set` seems like the most semantically correct Java collection type to use here, and so that's the conventional practice in the Hibernate community.

The catch associated with using a set is that we must carefully ensure that `Book` has a high-quality implementation of <<equals-and-hash>>.
Now, that's not necessarily a bad thing, since a quality `equals()` is independently useful.

But what if we used `Collection` or `List` instead?
Then our code would be much less sensitive to how `equals()` and `hashCode()` were implemented.

In the past, we were perhaps too dogmatic in recommending the use of `Set`.
Now? I guess we're happy to let you guys decide.
In hindsight, we could have done more to make clear that this was always a viable option.
****
====

[[one-to-one-fk]]
=== One-to-one (first way)

The simplest sort of one-to-one association is almost exactly like a `@ManyToOne` association, except that it maps to a foreign key column with a `UNIQUE` constraint.

[TIP]
// .One-to-many join table mappings
====
Later, we'll see how to map a one-to-one association to an <<join-table-mappings,association table>>.
====

A one-to-one association must be annotated `@OneToOne`:

[source,java]
----
@Entity
class Author {
    @Id @GeneratedValue
    Long id;

    @OneToOne(optional=false, fetch=LAZY)
    Person person;

    ...
}
----

Here, the `Author` table has a foreign key column holding the identifier of the associated `Person`.

[TIP]
// .One-to-one associations are a way to represent subtyping
====
A one-to-one association often models a "type of" relationship.
In our example, an `Author` is a type of `Person`.
An alternative—and often more natural—way to represent "type of" relationships in Java is via <<entity-inheritance,entity class inheritance>>.
====

We can make this association bidirectional by adding a reference back to the `Author` in the `Person` entity:

[source,java]
----
@Entity
class Person {
    @Id @GeneratedValue
    Long id;

    @OneToOne(mappedBy = Author_.PERSON)
    Author author;

    ...
}
----

`Person.author` is the unowned side, because it's the side marked `mappedBy`.

[NOTE]
====
Notice that we did not declare the unowned end of the association `fetch=LAZY`.
That's because:

1. not every `Person` has an associated `Author`, and
2. the foreign key is held in the table mapped by `Author`, not in the table mapped by `Person`.

Therefore, Hibernate can't tell if the reference from `Person` to `Author` is `null` without fetching the associated `Author`.

On the other hand, if _every_ `Person` was an `Author`, that is, if the association were non-`optional`, we would not have to consider the possibility of `null` references, and we would map it like this:

[source,java]
----
@OneToOne(optional=false, mappedBy = Author_.PERSON, fetch=LAZY)
Author author;
----
====

This is not the only sort of one-to-one association.

[[one-to-one-pk]]
=== One-to-one (second way)

An arguably more elegant way to represent such a relationship is to share a primary key between the two tables.

To use this approach, the `Author` class must be annotated like this:

[source,java]
----
@Entity
class Author {
    @Id
    Long id;

    @OneToOne(optional=false, fetch=LAZY)
    @MapsId
    Person person;

    ...
}
----

Notice that, compared with the previous mapping:

- the `@Id` attribute is no longer a `@GeneratedValue` and,
- instead, the `author` association is annotated `@MapsId`.

This lets Hibernate know that the association to `Person` is the source of primary key values for `Author`.

Here, there's no extra foreign key column in the `Author` table, since the `id` column holds the identifier of `Person`.
That is, the primary key of the `Author` table does double duty as the foreign key referring to the `Person` table.

The `Person` class doesn't change.
If the association is bidirectional, we annotate the unowned side `@OneToOne(mappedBy = Author_.PERSON)` just as before.

[[many-to-many]]
=== Many-to-many

A unidirectional many-to-many association is represented as a collection-valued attribute.
It always maps to a separate <<join-table-mappings,_association join table_>> in the database.

It tends to happen that a many-to-many association eventually turns out to be an entity in disguise.

[TIP]
====
Suppose we start with a nice clean many-to-many association between `Author` and `Book`.
Later on, it's quite likely that we'll discover some additional information which comes attached to the association, so that the association table needs some extra columns.

For example, imagine that we needed to report the percentage contribution of each author to a book.
That information naturally belongs to the association table.
We can't easily store it as an attribute of `Book`, nor as an attribute of `Author`.

When this happens, we need to change our Java model, usually introducing a new entity class which maps the association table directly.
In our example, we might call this entity something like `BookAuthorship`, and it would have `@OneToMany` associations to both `Author` and `Book`, along with the `contribution` attribute.

We can evade the disruption occasioned by such "discoveries" by simply avoiding the use of `@ManyToMany` right from the start.
There's little downside to representing every—or at least _almost_ every—logical many-to-many association using an intermediate entity.
====

A many-to-many association must be annotated `@ManyToMany`:

[source,java]
----
@Entity
class Book {
    @Id @GeneratedValue
    Long id;

    @ManyToMany
    Set<Author> authors;

    ...
}
----

If the association is bidirectional, we add a very similar-looking attribute to `Book`, but this time we must specify `mappedBy` to indicate that this is the unowned side of the association:

[source,java]
----
@Entity
class Book {
    @Id @GeneratedValue
    Long id;

    @ManyToMany(mappedBy=Author_.BOOKS)
    Set<Author> authors;
    
    ...
}
----

Remember, if we wish to the modify the collection we must <<bidirectional-problem,change the owning side>>.

We've again used ``Set``s to represent the association.
As before, we have the option to use `Collection` or `List`.
But in this case it _does_ make a difference to the semantics of the association.

[NOTE]
// .Sets and bags
====
A many-to-many association represented as a `Collection` or `List` may contain duplicate elements.
However, as before, the order of the elements is not persistent.
That is, the collection is a _bag_, not a set.
====

[WARNING]
====
We don't usually map collections with `fetch=EAGER`, since that usually leads to poor performance and fetching of unnecessary data.
But this is especially clear in the case of many-to-many associations.
We don't much employ the word "never" when it comes to object/relational mappings, but here we will:
**never** write `@ManyToMany(fetch=EAGER)` unless you're deliberately looking for trouble.
====

[[unidirectional-one-to-many]]
=== Unidirectional one-to-many

Finally, Hibernate allows a unidirectional one-to-many association, that is, a `@OneToMany` with no matching `@ManyToOne` on the other side.

[source,java]
----
@OneToMany // no matching @ManyToOne
Set<Book> books;
----

By default, a unidirectional one-to-many association maps to a separate <<join-table-mappings,association join table>>.
It therefore more closely resembles a many-to-many association than a many-to-one association.

[CAUTION]
====
If you're new to Hibernate, this is not the association mapping strategy you're looking for.
Use a <<many-to-one,bidirectional many-to-one>> instead.
Previous versions of this Guide advised against the use of these mappings completely.
====

Unidirectional one-to-many association mappings are only useful in one very specific circumstance.
Suppose we have a `Comment` entity, which has many different "parents" -- there can be comments on ``Document``s, comments on ``Issue``s, comments on ``Request``s, and so on.
These aren't many-to-many associations; each given `Comment` belongs to exactly one parent.
But on the other hand, it doesn't make sense to add a field for each kind of parent entity to the `Comment` class.
Nor does it make sense to add a foreign key column for each parent entity to the `COMMENTS` table.
This is the only scenario in which we can imagine ourselves using a unidirectional one-to-many.

[[collections]]
=== Collections of basic values and embeddable objects

We've now seen the following kinds of entity attribute:

[%breakable,cols="37,^15,^15,~"]
|===
| Kind of entity attribute | Kind of reference | Multiplicity | Examples

| Single-valued attribute of basic type | Non-entity | At most one | `@Basic String name`
| Single-valued attribute of embeddable type | Non-entity | At most one | `@Embedded Name name`
| Single-valued association | Entity | At most one |
`@ManyToOne Publisher publisher` +
`@OneToOne Person person`
| Many-valued association | Entity | Zero or more |
`@OneToMany Set<Book> books` +
`@ManyToMany Set<Author> authors`
|===

Scanning this taxonomy, you might ask: does Hibernate have multivalued attributes of basic or embeddable type?

Well, actually, we've already seen that it does, at least in two special cases.
So first, lets <<basic-attributes,recall>> that JPA treats `byte[]` and `char[]` arrays as basic types.
Hibernate persists a `byte[]` or `char[]` array to a `VARBINARY` or `VARCHAR` column, respectively.

But in this section we're really concerned with cases _other_ than these two special cases.
So then, _apart from ``byte[]`` and ``char[]``_, does Hibernate have multivalued attributes of basic or embeddable type?

And the answer again is that _it does_. Indeed, there are two different ways to handle such a collection, by mapping it:

- to a column of SQL `ARRAY` type (assuming the database has an `ARRAY` type), or
- to a separate table.

So we may expand our taxonomy with:

[%breakable,cols="37,^15,^15,~"]
|===
| Kind of entity attribute | Kind of reference | Multiplicity | Examples

| `byte[]` and `char[]` arrays | Non-entity | Zero or more |
`byte[] image` +
`char[] text`
| Collection of basic-typed elements | Non-entity | Zero or more |
`@Array String[] names` +
`@ElementCollection Set<String> names`
| Collection of embeddable elements | Non-entity | Zero or more |  `@ElementCollection Set<Name> names`
|===

There's actually two new kinds of mapping here: `@Array` mappings, and `@ElementCollection` mappings.

[%unbreakable]
[CAUTION]
// .These sorts of mappings are overused
====
These sorts of mappings are overused.

There _are_ situations where we think it's appropriate to use a collection of basic-typed values in our entity class.
But such situations are rare.
Almost every many-valued relationship should map to a foreign key association between separate tables.
And almost every table should be mapped by an entity class.

The features we're about to meet in the next two subsections are used much more often by beginners than they're used by experts.
So if you're a beginner, you'll save yourself some hassle by staying away from these features for now.
====

We'll talk about `@Array` mappings first.

[[arrays]]
=== Collections mapped to SQL arrays

Let's consider a calendar event which repeats on certain days of the week.
We might represent this in our `Event` entity as an attribute of type `DayOfWeek[]` or `List<DayOfWeek>`.
Since the number of elements of this array or list is upper bounded by 7, this is a reasonable case for the use of an `ARRAY`-typed column.
It's hard to see much value in storing this collection in a separate table.

[%unbreakable]
.*Read more: Learning to not hate SQL arrays*
[%collapsible]
====
****
For a long time, we thought arrays were a kind of weird and warty thing to add to the relational model, but recently we've come to realize that this view was overly closed-minded.
Indeed, we might choose to view SQL `ARRAY` types as a generalization of `VARCHAR` and `VARBINARY` to generic "element" types.
And from this point of view, SQL arrays look quite attractive, at least for certain problems.
If we're comfortable mapping `byte[]` to `VARBINARY(255)`, why would we shy away from mapping `DayOfWeek[]` to `TINYINT ARRAY[7]`?
****
====

Unfortunately, JPA doesn't define a standard way to map SQL arrays, but here's how we can do it in Hibernate:

[source, java]
----
@Entity
class Event {
    @Id @GeneratedValue
    Long id;
    ...
    @Array(length=7)
    DayOfWeek[] daysOfWeek;  // stored as a SQL ARRAY type
    ...
}
----

The `@Array` annotation is optional--it lets us specify an upper bound on the length of the `ARRAY` column.
By writing `@Array(length=7)` here, we specified that DDL should be generated with the column type `TINYINT ARRAY[7]`.

Just for fun, we used an enumerated type in the code above, but the array element time may be almost any <<basic-type-list,basic type>>.
For example, the Java array types `String[]`, `UUID[]`, `double[]`, `BigDecimal[]`, `LocalDate[]`, and `OffsetDateTime[]` are all allowed, mapping to the SQL types `VARCHAR(n) ARRAY`, `UUID ARRAY`, `FLOAT(53) ARRAY`, `NUMERIC(p,s) ARRAY`, `DATE ARRAY`, and `TIMESTAMP(p) WITH TIME ZONE ARRAY`, respectively.

[WARNING]
// .Not every database has an `ARRAY` type
====
Now for the gotcha: not every database has a SQL `ARRAY` type, and some that _do_ have an `ARRAY` type don't allow it to be used as a column type.
In particular, neither Db2 nor SQL Server have array-typed columns.
On these databases, Hibernate falls back to something quite a bit worse:
the array value is encoded to XML and stored in an XML-typed column.
====

Alternatively, we could store this array or list in a separate table.

[[element-collections]]
=== Collections mapped to a separate table

JPA _does_ define a standard way to map a collection to an auxiliary table: the `@ElementCollection` annotation.

[source, java]
----
@Entity
class Event {
    @Id @GeneratedValue
    Long id;
    ...
    @ElementCollection
    DayOfWeek[] daysOfWeek;  // stored in a dedicated table
    ...
}
----

Actually, we shouldn't use an array here, since array types can't be <<proxies-and-lazy-fetching,proxied>>, and so the JPA specification doesn't even say they're supported.
Instead, we should use `Set`, `List`, or `Map`.

[source, java]
----
@Entity
class Event {
    @Id @GeneratedValue
    Long id;
    ...
    @ElementCollection
    @OrderColumn
    List<DayOfWeek> daysOfWeek;  // stored in a dedicated table
    ...
}
----

Here, each collection element is stored as a separate row of the auxiliary table.
By default, this table has the following definition:

[source,sql]
----
create table Event_daysOfWeek (
    Event_id bigint not null,
    daysOfWeek tinyint check (daysOfWeek between 0 and 6),
    daysOfWeek_ORDER integer not null,
    primary key (Event_id, daysOfWeek_ORDER)
)
----

Which is fine, but it's still a mapping we prefer to avoid.

[%unbreakable]
[CAUTION]
// .This is not what we would do
====
`@ElementCollection` is one of our least-favorite features of JPA.
Even the name of the annotation is bad.

The code above results in a table with three columns:

- a foreign key of the `Event` table,
- a `TINYINT` encoding the `enum`, and
- an `INTEGER` encoding the ordering of elements in the array.

Instead of a surrogate primary key, it has a composite key comprising the foreign key of `Event` and the order column.

When--inevitably--we find that we need to add a fourth column to that table, our Java code must change completely.
Most likely, we'll realize that we need to add a separate entity after all.
So this mapping isn't very robust in the face of minor changes to our data model.
====

// [CAUTION]
// ====
// Consider the following very simple mapping:
// [source,java]
// ----
// @ElementCollection
// Set<String> topics;
// ----
// Hibernate would generate the following DDL:
// [source,sql]
// ----
// create table Book_topics (
//     Book_isbn varchar(255) not null,
//     topics varchar(255)
//     unique (Book_isbn, topics)
// )
// ----
// Here, there's no `not null` constraint on one of the columns.
// As a result, Hibernate cannot add a proper primary key to the table.
// This is not a great data model.
//
// We can fix this problem with a `@Column` annotation:
// [source,java]
// ----
// @ElementCollection
// @Column(nullable=false)
// Set<String> topics;
// ----
// Now the generated DDL looks better:
// [source,sql]
// ----
// create table Book_topics (
//     Book_isbn varchar(255) not null,
//     topics varchar(255) not null,
//     primary key (Book_isbn, topics)
// )
// ----
// Of course, with this mapping we can't have `null` as an element of our `Set`.
// But we can't think of a good reason why you might want that or what it would even mean for a set to contain null.
// ====

There's much more we could say about "element collections", but we won't say it, because we don't want to hand you the gun you'll shoot your foot with.

[[entities-summary]]
=== Summary of annotations

Let's pause to remember the annotations we've met so far.

.Declaring entities and embeddable types
[%breakable,cols="22,~,^13"]
|===
| Annotation | Purpose | JPA-standard

| `@Entity` | Declare an entity class | &#10004;
| `@MappedSuperclass` | Declare a non-entity class with mapped attributes inherited by an entity | &#10004;
| `@Embeddable` | Declare an embeddable type | &#10004;
| `@IdClass` | Declare the identifier class for an entity with multiple `@Id` attributes | &#10004;
|===

.Declaring basic and embedded attributes
[%breakable,cols="22,~,^10,^13"]
|===
| Annotation | Purpose | | JPA-standard

| `@Id` | Declare a basic-typed identifier attribute | | &#10004;
| `@Version` | Declare a version attribute | | &#10004;
| `@Basic` | Declare a basic attribute | Default | &#10004;
| `@EmbeddedId` | Declare an embeddable-typed identifier attribute | | &#10004;
| `@Embedded` | Declare an embeddable-typed attribute | Inferred | &#10004;
| `@Enumerated` | Declare an `enum`-typed attribute and specify how it is encoded | Inferred | &#10004;
| `@Array` | Declare that an attribute maps to a SQL `ARRAY`, and specify the length | Inferred | &#10006;
| `@ElementCollection` | Declare that a collection is mapped to a dedicated table | | &#10004;
|===

.Converters and compositional basic types
[%breakable,cols="22,~,^13"]
|===
| Annotation | Purpose | JPA-standard

| `@Converter` | Register an `AttributeConverter` | &#10004;
| `@Convert` | Apply a converter to an attribute | &#10004;
| `@JavaType` | Explicitly specify an implementation of `JavaType` for a basic attribute | &#10006;
| `@JdbcType` | Explicitly specify an implementation of `JdbcType` for a basic attribute | &#10006;
| `@JdbcTypeCode` | Explicitly specify a JDBC type code used to determine the `JdbcType` for a basic attribute | &#10006;
| `@JavaTypeRegistration` | Register a `JavaType` for a given Java type | &#10006;
| `@JdbcTypeRegistration` | Register a `JdbcType` for a given JDBC type code | &#10006;
|===

.System-generated identifiers
[%breakable,cols="22,~,^13"]
|===
| Annotation | Purpose | JPA-standard

| `@GeneratedValue` | Specify that an identifier is system-generated | &#10004;
| `@SequenceGenerator` | Define an id generator backed by a database sequence | &#10004;
| `@TableGenerator` | Define an id generated backed by a database table | &#10004;
| `@IdGeneratorType`  | Declare an annotation that associates a custom `Generator` with each `@Id` attribute it annotates | &#10006;
| `@ValueGenerationType` | Declare an annotation that associates a custom `Generator` with each `@Basic` attribute it annotates | &#10006;
|===

.Declaring entity associations
[%breakable,cols="22,~,^13"]
|===
| Annotation | Purpose | JPA-standard

| `@ManyToOne` | Declare the single-valued side of a many-to-one association (the owning side) | &#10004;
| `@OneToMany` | Declare the many-valued side of a many-to-one association (the unowned side) | &#10004;
| `@ManyToMany` | Declare either side of a many-to-many association | &#10004;
| `@OneToOne` | Declare either side of a one-to-one association | &#10004;
| `@MapsId` | Declare that the owning side of a `@OneToOne` association maps the primary key column | &#10004;
|===

Phew!
That's already a lot of annotations, and we have not even started with the annotations for O/R mapping!

[[equals-and-hash]]
=== `equals()` and `hashCode()`

Entity classes should override `equals()` and `hashCode()`, especially when associations are <<set-vs-list,represented as sets>>.

People new to Hibernate or JPA are often confused by exactly which fields should be included in the `hashCode()`.
And people with more experience often argue quite religiously that one or another approach is the only right way.
The truth is, there's no unique right way to do it, but there are some constraints.
So please keep the following principles in mind:

- You should not include a mutable field in the hashcode, since that would require rehashing every collection containing the entity whenever the field is mutated.
- It's not completely wrong to include a generated identifier (surrogate key) in the hashcode, but since the identifier is not generated until the entity instance is made persistent, you must take great care to not add it to any hashed collection before the identifier is generated. We therefore advise against including any database-generated field in the hashcode.

It's OK to include any immutable, non-generated field in the hashcode.

TIP: We therefore recommend identifying a <<natural-id-attributes,natural key>> for each entity, that is, a combination of fields that uniquely identifies an instance of the entity, from the perspective of the data model of the program. The natural key should correspond to a unique constraint on the database, and to the fields which are included in `equals()` and `hashCode()`.

In this example, the `equals()` and `hashCode()` methods agree with the `@NaturalId` annotation:

[source,java]
----
@Entity
class Book {

    @Id @GeneratedValue
    Long id;

    @NaturalId
    @Basic(optional=false)
    String isbn;

    String getIsbn() {
        return isbn;
    }

    ...

    @Override
    public boolean equals(Object other) {
        return other instanceof Book book    // check type with instanceof, not getClass()
            && book.getIsbn().equals(isbn);  // compare natural ids
    }
    @Override
    public int hashCode() {
        return isbn.hashCode();  // hashcode based on the natural id
    }
}
----

That said, an implementation of `equals()` and `hashCode()` based on the generated identifier of the entity can work _if you're careful_.

CAUTION: Your implementation of `equals()` must be written to accommodate the possibility that the object passed to the `equals()` might be a <<proxies-and-lazy-fetching,proxy>>.
Therefore, you should use `instanceof`, not `getClass()` to check the type of the argument, and should access fields of the passed entity via its accessor methods.

---

### Documentation Src Main Asciidoc Introduction Interacting (`documentation/src/main/asciidoc/introduction/Interacting.adoc`)

[[interacting]]
== Interacting with the database

To interact with the database, that is, to execute queries, or to insert, update, or delete data, we need an instance of one of the following objects:

- a JPA `EntityManager`,
- a JPA `EntityAgent`,
- a Hibernate `Session`, or
- a Hibernate `StatelessSession`.

The `Session` interface extends `EntityManager`, and so the only difference between the two interfaces is that `Session` offers a few more operations.
Similarly, `StatelessSession` extends `EntityAgent`.

[TIP]
// .The `Session` hiding inside an `EntityManager`
====
Actually, in Hibernate, every `EntityManager` is a `Session`, and you can narrow it like this:
[source,java]
----
Session session = entityManager.unwrap(Session.class);
----
Similarly, every `EntityAgent` is `StatelessSession`:
[source,java]
----
StatelessSession session = entityAgent.unwrap(StatelessSession.class);
----
====

An instance of `EntityManager` is a _stateful session_.
It mediates the interaction between your program and the database via operations on a _persistence context_.
In this chapter, we're going to focus on `EntityManager` first.
We'll <<bypass-persistence-context,come back>> to `EntityAgent` and _stateless sessions_ toward the end of the chapter.
What you need to know for now is that a stateless session doesn't have a persistence context.

Still, we should note for the record that some people prefer to use stateless sessions everywhere.
It's a simpler programming model, and lets the developer interact with the database more _directly_.
Stateful sessions certainly have their advantages, but they're more difficult to reason about, and when something goes wrong, the error messages can be more difficult to understand.

[[persistence-contexts]]
=== Persistence contexts

A persistence context is a sort of cache; we sometimes call it the "first-level cache", to distinguish it from the <<second-level-cache,second-level cache>>.
For every entity instance read from the database within the scope of a persistence context, and for every new entity made persistent within the scope of the persistence context, the context holds a unique mapping from the identifier of the entity instance to the instance itself.

Thus, an entity instance may be in one of three states with respect to a given persistence context:

1. _transient_ — never persistent, and not associated with the persistence context,
2. _persistent_ — currently associated with the persistence context, or
3. _detached_ — previously persistent in another session, but not currently associated with _this_ persistence context.

image::images/entity-lifecyle.png[Entity lifecycle,width=800,align="center"]

At any given moment, an instance may be associated with at most one persistence context.

The lifetime of a persistence context usually corresponds to the lifetime of a transaction, though it's possible to have a persistence context that spans several database-level transactions that form a single logical unit of work.

[WARNING]
====
A persistence context -- that is, a `Session` or `EntityManager` -- absolutely positively **must not be shared between multiple threads or between concurrent transactions.**

If you accidentally leak a session across threads, you will suffer.
====

[NOTE]
In a container environment, the lifecycle of a persistence context scoped to the transaction will usually be managed for you.

There are several reasons we like persistence contexts.

1. They help avoid _data aliasing_: if we modify an entity in one section of code, then other code executing within the same persistence context will see our modification.
2. They enable _automatic dirty checking_: after modifying an entity, we don't need to perform any explicit operation to ask Hibernate to propagate that change back to the database.
   Instead, the change will be automatically synchronized with the database when the session is <<flush,flushed>>.
3. They can improve performance by avoiding a trip to the database when a given entity instance is requested repeatedly in a given unit of work.
4. They make it possible to _transparently batch_ together multiple database operations.

A persistence context also allows us to detect circularities when performing operations on graphs of entities.
(Even in a stateless session, we need some sort of temporary cache of the entity instances we've visited while executing a query.)

On the other hand, stateful sessions come with some very important restrictions, since:

- persistence contexts aren't threadsafe, and can't be shared across threads, and
- a persistence context can't be reused across unrelated transactions, since that would break the isolation and atomicity of the transactions.

Furthermore, a persistence context holds a hard references to all its entities, preventing them from being garbage collected.
Thus, the session must be discarded once a unit of work is complete.

[IMPORTANT]
// .This is important
====
If you don't completely understand the previous passage, go back and re-read it until you do.
A great deal of human suffering has resulted from users mismanaging the lifecycle of the Hibernate `Session` or JPA `EntityManager`.
====

We'll conclude by noting that whether a persistence context helps or harms the performance of a given unit of work depends greatly on the nature of the unit of work.
For this reason Hibernate provides both stateful and stateless sessions.

[[creating-session]]
=== Creating a session

We saw how to obtain an `EntityManagerFactory` in <<configuration-jpa>> and <<configuration-api>>.
It's quite unsurprising that we may use this object to create an `EntityManager` or `EntityAgent`:

[source,java]
----
EntityManager entityManager = entityManagerFactory.createEntityManager();
----
[source,java]
----
EntityAgent entityAgent = entityManagerFactory.createEntityAgent();
----

When we're finished with the `EntityManager` or `EntityAgent`, we must explicitly clean it up:

[source,java]
----
entityManager.close();
----
[source,java]
----
entityAgent.close();
----

[CAUTION]
Even though an `EntityAgent` is a "stateless" session, the `EntityAgent` itself still holds state which must be cleaned up by calling `close()`.

// On the other hand, if we're starting from a `SessionFactory`, as described in <<configuration-api>>, we may use:
//
// [source,java]
// ----
// Session session = sessionFactory.openSession();
// ----
//
// But we still need to clean up:
//
// [source,java]
// ----
// session.close();
// ----

JPA 4 _session creation options_ let us provide some information controlling the behavior of the `EntityManager` or `EntityAgent` in a type safe way.

[source,java]
----
EntityManager entityManager =
        entityManagerFactory.createEntityManager(new FetchBatchSize(20),
                                                 ReadOnlyMode.READ_ONLY,
                                                 CacheStoreMode.BYPASS);
----

Search for implementations of `EntityManager.CreationOption` or `EntityAgent.CreationOption` to find the option types provided by the specification and by Hibernate.
A number of useful options are declared by link:{doc-javadoc-url}org/hibernate/SessionCreationOption.html[`SessionCreationOption`].

.*Read more: Injecting the EntityManager or EntityAgent*
[%collapsible]
====
****
If you're writing code for some sort of container environment, you'll probably obtain the `EntityManager` or `EntityAgent` by some sort of dependency injection.
For example, in Java (or Jakarta) EE you would write:

[source,java]
----
@PersistenceContext EntityManager entityManager;
----
[source,java]
----
@PersistenceAgent EntityAgent entityAgent;
----

In Quarkus, injection is handled by CDI:

[source,java]
----
@Inject EntityManager entityManager;
----
[source,java]
----
@Inject EntityAgent entityAgent;
----
****
====

Outside a container environment, we'll also have to write code to manage database transactions.

[[managing-transactions]]
=== Managing transactions

Using JPA-standard APIs, the `EntityTransaction` interface allows us to control database transactions.
The idiom we recommend is the following:

[source,java]
----
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction tx = entityManager.getTransaction();
try {
    tx.begin();
    //do some work
    ...
    tx.commit();
}
catch (Exception e) {
    if (tx.isActive()) tx.rollback();
    throw e;
}
finally {
    entityManager.close();
}
----

But this code is extremely tedious, so there's a cleaner option:

[source,java]
----
entityManagerFactory.runInTransaction(entityManager -> {
    // do the work in a stateful session
    ...
});
----

When we need to return a value from within the anonymous function, we use `callInTransaction()` instead of `runInTransaction()`.

In case we're using an `EntityAgent`, or if we would like direct access to the `Session` or `StatelessSession` without a type cast, `runInTransaction()` lets us specify the class of session we require:

[source,java]
----
entityManagerFactory.runInTransaction(EntityAgent.class, entityAgent -> {
    // do the work in a stateless session
    ...
});
----
[source,java]
----
entityManagerFactory.runInTransaction(Session.class, session -> {
    // do the work in a Hibernate session
    ...
});
----

// Using Hibernate's native APIs we can write something very similar:
// // [source,java]
// // ----
// // Session session = sessionFactory.openSession();
// // Transaction tx = null;
// // try {
// //     tx = session.beginTransaction();
// //     //do some work
// //     ...
// //     tx.commit();
// // }
// // catch (Exception e) {
// //     if (tx!=null) tx.rollback();
// //     throw e;
// // }
// // finally {
// //     session.close();
// // }
// // ----
// [source,java]
// ----
// sessionFactory.inTransaction(session -> {
//     //do the work
//     ...
// });
// ----

[NOTE]
====
In a container environment, the container itself is usually responsible for managing transactions.
In Java EE or Quarkus, you'll probably indicate the boundaries of the transaction using the `@Transactional` annotation.
====

The `EntityTransaction` interface provides a standard way to set the transaction timeout:

[source,java]
----
entityManager.getTransaction().setTimeout(30); // 30 seconds
----

`EntityTransaction` also provides a way to set the transaction to rollback-only mode:

[source,java]
----
entityManager.getTransaction().setRollbackOnly();
----

A transaction in rollback-only mode will be rolled back when it completes.

[[after-tx-rollback]]
[IMPORTANT]
====
Hibernate is not a software transactional memory.
When a transaction rolls back, Hibernate makes no attempt to roll back the state of objects held in memory to their state at the beginning of the transaction.
After a transaction rollback, the persistence context must be discarded, and the state of its entities must be assumed inconsistent with the state held by the database.
====

The interface link:{doc-javadoc-url}org/hibernate/Transaction.html[`Transaction`] extends `EntityTransaction` with some additional operations, including the ability to register transaction completion callbacks.

[[persistence-operations]]
=== Operations on the persistence context

Of course, the main reason we need an `EntityManager` is to do stuff to the database.
The following important operations let us interact with the persistence context and schedule modifications to the data:

.Methods for modifying data and managing the persistence context
[%breakable,cols="30,~"]
|===
| Method name and parameters | Effect

| `persist(Object)`
| Make a transient object persistent and schedule a SQL `insert` statement for later execution
| `remove(Object)`
| Make a persistent object transient and schedule a SQL `delete` statement for later execution
| `merge(Object)`
| Copy the state of a given detached object to a corresponding managed persistent instance and return
the persistent object
| `detach(Object)`
| Disassociate a persistent object from a session without
affecting the database
| `clear()`
| Empty the persistence context and detach all its entities
| `flush()`
| Detect changes made to persistent objects association with the session and synchronize the database state with the state of the session by executing SQL `insert`, `update`, and `delete` statements
|===

Notice that `persist()` and `remove()` usually have no immediate effect on the database, and instead simply schedule a command for later execution.
Also notice that there's no `update()` operation for a stateful session.
Modifications are automatically detected when the session is <<flush,flushed>>.

On the other hand, except for `getReference()`, the following operations all result in immediate access to the database:

[[methods-for-reading]]
.Methods for reading and locking data
[%breakable,cols="30,~"]
|===
| Method name and parameters | Effect

| `get(Class,Object)`
| Obtain a persistent object given its type and its id, throwing `EntityNotFoundException` if there is no such record
| `find(Class,Object)`,
| Obtain a persistent object given its type and its id, returning `null` if there is no such record
// | `find(Class,Object,LockModeType)`
// | Obtain a persistent object given its type and its id, requesting the given <<optimistic-and-pessimistic-locking,optimistic or pessimistic lock mode>>
returning `null` if there is no such record
| `getReference(Class,id)`
| Obtain a reference to a persistent object given its type and its id, without actually loading its state from the database
| `getReference(Object)`
| Obtain a reference to a persistent object with the same identity as the given detached instance, without actually loading its state from the database
| `refresh(Object)`
| Refresh the persistent state of an object using a new SQL `select` to retrieve its current state from the database
// | `refresh(Object,LockModeType)`
// | Refresh the persistent state of an object using a new SQL `select` to retrieve its current state from the database, requesting the given <<optimistic-and-pessimistic-locking,optimistic or pessimistic lock mode>>
| `lock(Object,LockModeType)`
| Obtain an <<optimistic-and-pessimistic-locking,optimistic or pessimistic lock>> on a persistent object
|===

Any of these operations might throw an exception.
Now, if an exception occurs while interacting with the database, there's no good way to resynchronize the state of the current persistence context with the state held in database tables.

Therefore, a session is considered to be unusable after any of its methods throws an exception.

[[fragile-persistence-context]]
[IMPORTANT]
// .The persistence context is fragile
====
The persistence context is fragile.
If you receive an exception from Hibernate, you should immediately close and discard the current session. Open a new session if you need to, but throw the bad one away first.
====

One very important kind of exception which can happen when data is shared between concurrent units of work is an _optimistic lock failure_.
Optimistic locks are verified by checking <<version-attributes,versions>>.
A version check is included in the `where` clause of every SQL `update` or `delete` statement for a versioned entity.
If a version check fails--that is, if no rows are updated--Hibernate infers that the entity was updated in some other unit of work and throws an `OptimisticLockException` to indicate that the current session is working with stale data.
As with other exceptions, this loss of synchronization between the persistence context and the database means that we must discard the current session.

[CAUTION]
====
Some of these operations listed above require slightly more care than others.
When you call `detach()`, `clear()`, `flush()`, or `refresh()`, you've already strayed from the narrow path.
You didn't stray far--and you probably had a good reason for going there--but you're in territory where Hibernate just has to assume you know what you're doing.
If you start to feel that this terrain is bogging you down, consider using a <<stateless-sessions,stateless session>>.
====

Four of these operations accept _options_, allowing influence over their behavior.

[%breakable,cols="50,~"]
|===
| Method name and parameters | Effect

| `get(Class,Object,FindOption...)`
| Obtain a persistent object given its type and its id, using the specified options, throwing if there is no such record
| `get(EntityGraph,Object,FindOption...)`
| Obtain a persistent object given its id and an `EntityGraph` specifying its type and associations which should be eagerly fetched, using the specified options, throwing if there is no such record
| `find(Class,Object,FindOption...)`
| Obtain a persistent object given its type and its id, using the specified options, returning `null` there is no such record
| `find(EntityGraph,Object,FindOption...)`
| Obtain a persistent object given its id and an `EntityGraph` specifying its type and associations which should be eagerly fetched, using the specified options, returning `null` there is no such record
| `refresh(Object,LockModeType,RefreshOption...)`
| Refresh the persistent state of an object using a new SQL `select` to retrieve its current state from the database, requesting the given <<optimistic-and-pessimistic-locking,optimistic or pessimistic lock mode>>, using the specified options
| `lock(Object,LockModeType,LockOption...)`
| Obtain an <<optimistic-and-pessimistic-locking,optimistic or pessimistic lock>> on a persistent object, using the specified options
|===

For example, JPA provides the `Timeout` class which is a `FindOption`, a `RefreshOption`, and a `LockOption`.

[source,java]
----
var book = entityManger.find(Book.class, isbn, Timeout.ms(100), CacheStoreMode.BYPASS);
----

Finally, the following methods are capable of efficiently loading multiple entity instances in parallel:

[%breakable,cols="50,~"]
|===
| Method name and parameters | Effect

| `getMultiple(Class,List<Object>,FindOption...)`
| Obtain a list of persistent objects given their type and their ids, using the specified options, throwing if there is no such record
| `getMultiple(EntityGraph,List<Object>,FindOption...)`
| Obtain a list of persistent objects given their ids and an `EntityGraph` specifying their type and associations which should be eagerly fetched, using the specified options, throwing if there is no such record
| `findMultiple(Class,List<Object>,FindOption...)`
| Obtain a list of persistent objects given their type and their ids, using the specified options, returning `null` there is no such record
| `findMultiple(EntityGraph,List<Object>,FindOption...)`
| Obtain a list of persistent objects given their ids and an `EntityGraph` specifying their type and associations which should be eagerly fetched, using the specified options, returning `null` there is no such record
|===

The following code results in a single SQL `select` statement:

[source,java]
----
List<Book> books = entityManger.findMultiple(Book.class, bookIds);
----

link:{doc-javadoc-url}org/hibernate/FindMultipleOption.html[`FindMultipleOption`] declares a number of options influencing the behavior of `findMultiple()` and `getMultiple()`.

[[load-by-natural-id]]
=== Lookup by natural id
As discussed <<natural-id-attributes,earlier>>, Hibernate offers the ability to map a natural id and perform retrieval operations using the natural id.
This is accomplished using the option link:{doc-javadoc-url}org/hibernate/KeyType.html#NATURAL[`KeyType.NATURAL`]:

[source,java]
----
var bookKey = new BookKey(isbn, printing);
var book = entityManager.find(Book.class, bookKey, KeyType.NATURAL);
----

In this example, `BookKey` is the link:{doc-javadoc-url}org/hibernate/annotations/NaturalIdClass.html[`@NaturalIdClass`] for `Book`.
If an entity with a composite natural id lacks a natural id class, a `Map` may be used instead:

[source,java]
----
var bookKey = Map.of(Book_.ISBN, isbn, Book_.PRINTING, printing);
var book = entityManager.find(Book.class, bookKey, KeyType.NATURAL);
----

Each of the operations we've seen so far affects a single entity instance passed as an argument.
But there's a way to set things up so that an operation will propagate to associated entities.

[[cascade]]
=== Cascading persistence operations

It's quite often the case that the lifecycle of a _child_ entity is completely dependent on the lifecycle of some _parent_.
This is especially common for many-to-one and one-to-one associations, though it's very rare for many-to-many associations.

For example, it's quite common to make an `Order` and all its ``Item``s persistent in the same transaction, or to delete a `Project` and its ``Files``s at once.
This sort of relationship is sometimes called a _whole/part_-type relationship.

_Cascading_ is a convenience which allows us to propagate one of the operations listed in <<persistence-operations>> from a parent to its children.
To set up cascading, we specify the `cascade` member of one of the association mapping annotations, usually `@OneToMany` or `@OneToOne`.

[source,java]
----
@Entity
class Order {
    ...
    @OneToMany(mappedby=Item_.ORDER,
               // cascade persist(), remove(), and refresh() from Order to Item
               cascade={PERSIST,REMOVE,REFRESH},
               // also remove() orphaned Items
               orphanRemoval=true)
    private Set<Item> items;
    ...
}
----

_Orphan removal_ indicates that an `Item` should be automatically deleted if it is removed from the set of items belonging to its parent `Order`.

[[proxies-and-lazy-fetching]]
=== Proxies and lazy fetching

Our data model is a set of interconnected entities, and in Java our whole dataset would be represented as an enormous interconnected graph of objects.
It's possible that this graph is disconnected, but more likely it's connected, or composed of a relatively small number of connected subgraphs.

Therefore, when we retrieve an object belonging to this graph from the database and instantiate it in memory, we simply can't recursively retrieve and instantiate all its associated entities.
Quite aside from the waste of memory on the VM side, this process would involve a huge number of round trips to the database server, or a massive multidimensional cartesian product of tables, or both.
Instead, we're forced to cut the graph somewhere.

Hibernate solves this problem using _proxies_ and _lazy fetching_.
A proxy is an object that masquerades as a real entity or collection, but doesn't actually hold any state, because that state has not yet been fetched from the database.
When you call a method of the proxy, Hibernate will detect the call and fetch the state from the database before allowing the invocation to proceed to the real entity object or collection.

Now for the gotchas:

1. Hibernate only does this for an entity which is currently associated with a persistence context.
   Once the session ends, and the persistence context is cleaned up, the proxy is no longer fetchable, and instead its methods throw the hated `LazyInitializationException`.
2. For a polymorphic association, Hibernate does not know the concrete type of the referenced entity when the proxy is instantiated, and so operations like `instanceof` and typecasts do not work correctly when applied to a proxy.
3. A round trip to the database to fetch the state of a single entity instance is just about _the least efficient_ way to access data.
   It almost inevitably leads to the infamous _N+1 selects_ problem we'll discuss later when we talk about how to <<association-fetching,optimize association fetching>>.

[TIP]
====
The link:{doc-javadoc-url}org/hibernate/annotations/ConcreteProxy.html[`@ConcreteProxy`] annotation solves gotcha 2, but at the cost of performance (extra joins), and so its use is not generally recommended, except in very special circumstances.
====

[TIP]
// .Strive to avoid triggering lazy fetching
====
We're getting a bit ahead of ourselves here, but let's quickly mention the general strategy we recommend to navigate past these gotchas:

- All associations should be set `fetch=LAZY` to avoid fetching extra data when it's not needed.
  As we mentioned <<lazy-problem,earlier>>, this setting is not the default for `@ManyToOne` associations, and must be specified explicitly unless the default is changed using `<default-to-one-fetch-type>` or `defaultToOneFetchType()`.
- But strive to avoid writing code which triggers lazy fetching.
  Instead, fetch all the data you'll need upfront at the beginning of a unit of work, using one of the techniques described in <<association-fetching>>, usually, using _join fetch_ in HQL or an `EntityGraph`.
====

It's important to know that some operations which may be performed with an unfetched proxy _don't_ require fetching its state from the database.
First, we're always allowed to obtain its identifier:

[source,java]
----
var pubId = entityManager.find(Book.class, bookId).getPublisher().getId(); // does not fetch publisher
----

Second, we may create an association to a proxy:

[source,java]
----
book.setPublisher(entityManager.getReference(Publisher.class, pubId)); // does not fetch publisher
----

Sometimes it's useful to test whether a proxy or collection has been fetched from the database.
JPA lets us do this using the `PersistenceUnitUtil`:

[source,java]
----
boolean authorsFetched = entityManagerFactory.getPersistenceUnitUtil().isLoaded(book.getAuthors());
----

Hibernate has a slightly easier way to do it:

[source,java]
----
boolean authorsFetched = Hibernate.isInitialized(book.getAuthors());
----

Similarly, `PersistenceUnitUtil.load()` force-fetches a proxy or collection:

[source,java]
----
Book book = entityManager.find(Book.class, bookId);  // fetch just the Book, leaving authors unfetched
entityManagerFactory.getPersistenceUnitUtil().load(book.getAuthors());
----

Again, `Hibernate.initialize()` is slightly more convenient:

[source,java]
----
Book book = session.find(Book.class, bookId);  // fetch just the Book, leaving authors unfetched
Hibernate.initialize(book.getAuthors());  // fetch the Authors
----

On the other hand, the above code is very inefficient, requiring two trips to the database to obtain data that could in principle be retrieved with just one query.

The static methods of the link:{doc-javadoc-url}org/hibernate/Hibernate.html[`Hibernate`] class let us do a lot more, and it's worth getting a bit familiar with them.
Of particular interest are the operations which let us work with unfetched collections without fetching their state from the database.
For example, consider this code:

[source,java]
----
Book book = session.find(Book.class, bookId);  // fetch just the Book, leaving authors unfetched
Author authorRef = session.getReference(Author.class, authorId);  // obtain an unfetched proxy
boolean isByAuthor = Hibernate.contains(book.getAuthors(), authorRef); // no fetching
----

This code fragment leaves both the set `book.authors` and the proxy `authorRef` unfetched.

It's clear from the discussion above that we need a way to request that an association be _eagerly_ fetched using a database `join`, thus protecting ourselves from the infamous N+1 selects.
One way to do this is by passing an `EntityGraph` to `find()`.

[[entity-graph]]
=== Entity graphs and eager fetching

When an association is mapped `fetch=LAZY`, it won't, by default, be fetched when we call the `find()` method.
We may request that an association be fetched eagerly (immediately) by passing an `EntityGraph` to `find()`.

[source,java]
----
var graph = entityManager.createEntityGraph(Book.class);
graph.addSubgraph(Book_.publisher);
Book book = entityManager.find(graph, bookId);
----

//
// [source,java]
// ----
// var graph = session.createEntityGraph(Book.class);
// graph.addSubgraph(Book_.publisher);
// Book book = session.byId(Book.class).withFetchGraph(graph).load(bookId);
// ----

This code adds a `left outer join` to our SQL query, fetching the associated `Publisher` along with the `Book`.

We may even attach additional nodes to our `EntityGraph`:

[source,java]
----
var graph = entityManager.createEntityGraph(Book.class);
graph.addSubgraph(Book_.publisher);
graph.addPluralSubgraph(Book_.authors).addSubgraph(Author_.person);
Book book = entityManager.find(graph, bookId);
----

// [source,java]
// ----
// var graph = session.createEntityGraph(Book.class);
// graph.addSubgraph(Book_.publisher);
// graph.addPluralSubgraph(Book_.authors).addSubgraph(Author_.person);
// Book book = session.byId(Book.class).withFetchGraph(graph).load(bookId);
// ----

This results in a SQL query with _four_ ``left outer join``s.

Instances of `FetchOption` influence how a node of a graph is fetched.

[source,java]
----
var graph = entityManager.createEntityGraph(Book.class);
graph.addAttributeNode(Book_.publisher)
     .addOption(FetchMethod.BULK_SELECT)
     .addOption(CacheStoreMode.BYPASS);
Book book = entityManager.find(graph, bookId);
----

[NOTE]
====
In the code examples above, The classes `Book_` and `Author_` are generated by <<metamodel-generator,Hibernate Processor>>, as we saw <<mapped-by-metamodel,earlier>>.
They let us refer to attributes of our model in a completely type-safe way.
We'll use them again, below, when we talk about <<criteria-queries>>.
====

.*Read more: Fetch graphs and load graphs*
[%collapsible]
====
****
JPA specifies that any given `EntityGraph` may be interpreted in two different ways.

- A _fetch graph_ specifies exactly the associations that should be eagerly loaded.
  Any association not belonging to the entity graph is proxied and loaded lazily only if required.
- A _load graph_ specifies that the associations in the entity graph are to be fetched in addition to the associations mapped `fetch=EAGER`.

An `EntityGraph` passed directly to `find()` is always interpreted as a load graph.

You're right, the names make no sense.
But don't worry, if you take our advice, and map your associations `fetch=LAZY`, there's no difference between a "fetch" graph and a "load" graph, so the names don't matter.
****
====

[TIP]
====
JPA even specifies a way to define named entity graphs using annotations.
The annotation-based API used to be so verbose that it just not wasn't worth using.
However, in JPA 4 this API has been much improved via introduction of the `@Fetch` annotation.
So perhaps you'll find a use for it.
You'll find more information in the Javadoc for `@NamedEntityGraph`.
====

// [[load-access]]
// === Controlling lookup by id
//
// As we will soon see in the <<queries,next chapter>>, we can do almost anything via <<hql-queries,HQL>>, <<criteria-queries,criteria>>, or <<native-queries,native SQL>> queries.
// But when we already know the identifier of the entity we need, a query can feel like overkill.
// And queries don't make efficient use of the <<second-level-cache,second level cache>>.
//
// We met the `find()` and `findMultiple()` methods <<persistence-operations,earlier>>.
// These are the most basic ways to perform a _lookup_ by id.
// But they can't quite do everything.
// Therefore, Hibernate has some APIs that streamline certain more complicated lookups:
//
// .Operations for lookup by id
// [%breakable,cols="30,~"]
// |===
// | Method name | Purpose
//
// | `byId()` | Lets us specify association fetching via an `EntityGraph`, as we saw; also lets us specify some additional options, including how the lookup <<second-level-cache-management,interacts with the second level cache>>, and whether the entity should be loaded in read-only mode
// | `byMultipleIds()` | Lets us load a _batch_ of ids at the same time
// |===
//
// [NOTE]
// ====
// Since the introduction of `FindOption` in JPA 3.2, `byId()` is now much less useful and deprecated.
// Instead, use `find()` and `findMultiple()` as discussed <<methods-for-reading,earlier>>.
// ====
//
// Batch loading is very useful when we need to retrieve multiple instances of the same entity class by id:
//
// [source,java]
// ----
// var graph = session.createEntityGraph(Book.class);
// graph.addSubgraph(Book_.publisher);
//
// List<Book> books =
//         session.byMultipleIds(Book.class)
//             .withFetchGraph(graph)  // control association fetching
//             .withBatchSize(20)      // specify an explicit batch size
//             .with(CacheMode.GET)    // control interaction with the cache
//             .multiLoad(bookIds);
// ----
//
// The given list of `bookIds` will be broken into batches, and each batch will be fetched from the database in a single `select`.
// If we don't specify the batch size explicitly, a batch size will be chosen automatically.
//
// We also have some operations for working with lookups by <<natural-identifiers, natural id>>:
//
// [%breakable,cols="30,~"]
// |===
// | Method name | Purpose
//
// | `bySimpleNaturalId()` | For an entity with just one attribute is annotated `@NaturalId`
// | `byNaturalId()` | For an entity with multiple attributes are annotated `@NaturalId`
// | `byMultipleNaturalId()` | Lets us load a _batch_ of natural ids at the same time
// |===
//
// Again, see the link:{doc-user-guide-url}#find-by-natural-id[User Guide] for more details about loading by natural ids.
//
// Here's how we can retrieve an entity by its composite natural id:
//
// [source,java]
// ----
// Book book =
//         session.byNaturalId(Book.class)
//             .using(Book_.isbn, isbn)
//             .using(Book_.printing, printing)
//             .load();
// ----
//
// Notice that this code fragment is completely typesafe, again thanks to <<metamodel-generator,Hibernate Processor>>.

[[controlling-merge]]
=== Controlling state retrieval during merge

The <<persistence-operations,`merge()`>> operation is usually used when some interaction with a user or automated system spans multiple transactions, with each transaction having its own persistence context:

1. an entity `e` is retrieved in one persistence context, and then the current transaction ends, resulting in destruction of the persistence context and in the entity becoming detached, then
2.  `e` is modified in some way while detached, and then
3. finally, the modification is made persistent by merging the detached instance in a second transaction, with a new persistence context, by calling `entityManager.merge(e)`.

In step 3, the original entity instance `e` remains detached, but `merge()` returns a distinct instance `f` representing the same row of the database and associated with the new persistence context.
That is, `merge()` trades a detached instance for a <<persistence-contexts,persistent instance>> representing the same row.

To determine the nature of the modification held in `e` and to guarantee correct semantics with respect to optimistic locking, Hibernate first ``select``s the current persistent state of the entity from the database before applying the modification to `f`.

<<cascade,Cascade merge>> allows multiple modifications held in a graph of entity instances to be made persistent in one call to `merge()`.
When `merge()` is used with cascading -- that is, when the `merge()` operation is applied to a root entity with associations mapped `cascade=MERGE` -- Hibernate issues a single `select` statement to retrieve the current database state of the root entity and all its associated entities.
This behavior avoids the use of N+1 select statements for state retrieval during cascade merge but, in certain circumstances, the query might be suboptimal.
On the other hand, this query does not occur if the root entity was already loaded into the persistence context before `merge()` is called.

Therefore, when using the `EntityManager` API, we may gain control over the way state is loaded before a `merge()` just by calling `find()` before calling `merge()`.

[source,java]
----
Book book = ... ;
var graph = entityManager.createEntityGraph(Book.class);
graph.addSubgraph(Book_.chapters);  // Book.chapters mapped cascade=MERGE
entityManager.find(graph, book.getIsbn());  // force loading of the book
entityManager.merge(book);  // merge the detached objet
----

The `Session` interface provides a streamlined alternative:

[source,java]
----
Book book = ... ;
var graph = session.createEntityGraph(Book.class);
graph.addSubgraph(Book_.chapters);
session.merge(book, graph);  // equivalent to find() then merge()
----

When merging multiple root entities, `findMultiple()` may be used instead of `find()`.

[source,java]
----
List<Book> books = ... ;
var isbns = books.stream().map(Book::getIsbn).toList();
var graph = entityManager.createEntityGraph(Book.class);
graph.addSubgraph(Book_.chapters);  // Book.chapters mapped cascade=MERGE
entityManager.findMultiple(graph, isbns);  // force loading of the books
for (var book in books) {
    entityManager.merge(book);
}
----

TIP: In some cases, `merge()` is much less efficient than the <<bypass-persistence-context,`upsert()`>> operation of `EntityAgent`.

[[flush]]
=== Flushing the session

From time to time, a _flush_ operation is triggered, and the session synchronizes dirty state held in memory—that is, modifications to the state of entities associated with the persistence context—with persistent state held in the database. Of course, it does this by executing SQL `INSERT`, `UPDATE`, and `DELETE` statements.

By default, a flush is triggered:

- when the current transaction commits, for example, when `Transaction.commit()` is called,
- before execution of a query whose result would be affected by the synchronization of dirty state held in memory, or
- when the program directly calls `flush()`.

In the following code, the flush occurs when the transaction commits:

[source,java]
----
entityManager.getTransaction().begin();
entityManager.persist(author);
var books =
        // new Author does not affect results of query for Books
        entityManager.createQuery("from Book", Book.class)
                // no need to flush
                .getResultList();
// flush occurs here, just before transaction commits
entityManager.getTransaction().commit();
----

But in this code, the flush occurs when the query is executed:

[source,java]
----
entityManager.getTransaction().begin();
entityManager.persist(book);
var books =
        // new Book would affect results of query for Books
        entityManager.createQuery("from Book", Book.class)
                // flush occurs here, just before query is executed
                .getResultList();
// changes were already flushed to database, nothing to flush
entityManager.getTransaction().commit();
----

It's always possible to call `flush()` explicitly:

[source,java]
----
entityManager.getTransaction().begin();
entityManager.persist(author);
entityManager.flush(); // explicit flush
var books =
        entityManager.createQuery("from Book", Book.class)
                // nothing to flush
                .getResultList();
// nothing to flush
entityManager.getTransaction().commit();
----

[NOTE]
// .SQL execution happens asynchronously
====
Notice that SQL statements are not usually executed synchronously by methods of the `Session` interface like `persist()` and `remove()`. If synchronous execution of SQL is desired, the `StatelessSession` allows this.
====

This behavior can be controlled by explicitly setting the flush mode.
For example, to disable flushes that occur before query execution, call:

[source,java]
----
entityManager.setFlushMode(FlushModeType.COMMIT);
----

// Hibernate allows greater control over the link:{doc-javadoc-url}org/hibernate/FlushMode.html[flush mode] than JPA:
//
// [source,java]
// ----
// session.setHibernateFlushMode(FlushMode.MANUAL);
// ----

Since flushing is a somewhat expensive operation (the session must dirty-check every entity in the persistence context), setting the flush mode to `COMMIT` can occasionally be a useful optimization.
But take care--in this mode, queries might return stale data:

[source,java]
----
entityManager.getTransaction().begin();
entityManager.setFlushMode(FlushModeType.COMMIT); // disable AUTO-flush
entityManager.persist(book);
var books =
        // flushing on query execution disabled
        entityManager.createQuery("from Book", Book.class)
                // no flush, query returns stale results
                .getResultList();
// flush occurs here, just before transaction commits
entityManager.getTransaction().commit();
----

.Flush modes
[%breakable,cols="15,15,~"]
|===
| Hibernate link:{doc-javadoc-url}org/hibernate/FlushMode.html[`FlushMode`] | JPA `FlushModeType` | Interpretation

| `MANUAL` | `EXPLICIT` | Never flush automatically
| `COMMIT` | `COMMIT` | Flush before transaction commit
| `AUTO` | `AUTO` | Flush before transaction commit, and before execution of a query whose results might be affected by modifications held in memory
| `ALWAYS` | | Flush before transaction commit, and before execution of every query
|===

A second way to reduce the cost of flushing is to load entities in link:{doc-javadoc-url}org/hibernate/Session.html#setDefaultReadOnly(boolean)[_read-only_ mode].
// - `Session.setDefaultReadOnly(true)` specifies that all entities loaded by a given session should be loaded in read-only mode by default,
// - `SelectionQuery.setReadOnly(true)` specifies that every entity returned by a given query should be loaded in read-only mode, and
// - `Session.setReadOnly(Object, true)` specifies that a given entity already loaded by the session should be switched to read-only mode.
The custom option link:{doc-javadoc-url}org/hibernate/ReadOnlyMode.html[`ReadOnlyMode`] may be used to control read-only mode:

[source,java]
----
// load a single entity in read-only mode
var book = entityManager.find(Book.class, isbn, ReadOnlyMode.READ_ONLY);
----
[source,java]
----
// load all query results in read-only mode
var books =
        entityManager.createQuery("from Book")
                .ofType(Book.class)
                .addOption(ReadOnlyMode.READ_ONLY)
                .getResultList();
----
[source,java]
----
// load every entity in read-only mode
entityManager.addOption(ReadOnlyMode.READ_ONLY);
----

It's not necessary to dirty-check an entity instance in read-only mode.
Indeed, read-only mode is a way to make a stateful session work a bit more like a stateless session, bypassing some of the overhead associated with the use of a persistence context.

[[bypass-persistence-context]]
=== Operations which bypass the persistence context

When we use an `EntityAgent`, we're always working with detached objects.
Thus, the programming model is a bit different to what we've just seen.
The methods for retrieving entities and querying the database are the same -- indeed, they're all declared by a common supertype named `EntityHandler` -- but these operations always return detached objects, and so lazy fetching is an explicit operation.
And the operations used to update the database are completely different.

.Important methods of the `EntityAgent`
[%autowidth.stretch]
|===
| Method name and parameters | Effect

| `fetch(Object)`      | Fetch an association of a detached object
| `refresh(Object)`    | Refresh the state of a detached object by executing
a `select`
| `insert(Object)`     | Immediately `insert` the state of the given transient object into the database
| `update(Object)`     | Immediately `update` the state of the given detached object in the database
| `delete(Object)`     | Immediately `delete` the state of the given detached object from the database
| `upsert(Object)`     | Immediately `insert` or `update` the state of the given detached object using a SQL `merge into` statement
|===

NOTE: The operations of a `EntityAgent` have no corresponding ``CascadeType``s, and so these operations never cascade to associated entity instances.

NOTE: There's no `flush()` operation, and so `update()` is always explicit.

Notice that all the operations listed above result in an immediate interaction with the database.
In certain circumstances, this makes stateless sessions easier to work with and simpler to reason about, but with the caveat that a stateless session is much more vulnerable to data aliasing effects, since it's easy to get two non-identical Java objects which both represent the same row of a database table.

Consider the following fragments:

[source,java]
----
var b1 = statelessSession.get(Book.class, isbn);
var b2 = statelessSession.get(Book.class, isbn);
assert b1 == b2;  // fails
----
[source,java]
----
var b1 = statelessSession.get(Book.class, isbn);
var b2 = statelessSession.get(Book.class, isbn);
statelessSession.fetch(b1.publisher);
statelessSession.fetch(b2.publisher);
assert b1.publisher == b2.publisher;  // fails
----

In a stateful session, entity instances are canonicalized by primary key, and so we don't usually have two different objects representing a single row.
No such canonicalization exists across invocations of a stateless session.
In a stateless session, both the assertions fail.

[%unbreakable]
[CAUTION]
====
If we use `fetch()` in a stateless session, we can very easily obtain two objects representing the same database row!
====

[[callbacks]]
=== Lifecycle callbacks and entity listeners

Lifecycle callbacks allow the application program to respond to events occurring deep within Hibernate.

- The annotations `@PrePersist`, `@PreRemove`, `@PreMerge`, `@PostPersist`, `@PostRemove`, `@PostMerge`, and `@PostLoad` allow an entity to respond to persistence lifecycle operations and maintain its transient internal state.
  These events only occur in a stateful session.

- The annotations `@PreInsert`, `@PreUpdate`, `@PreUpsert`, `@PreDelete`, `@PostInsert`,`@PostUpdate`, `@PostUpsert`, and `@PostDelete` allow the application program to be notified of operations executed against the database.
  These events occur in both stateful and stateless sessions.

For example:

[source,java]
----
@Entity
class Order {
    ...
    transient double total;

    @PostLoad
    void computeTotal() {
        total = items.stream().mapToDouble(i -> i.price * i.quantity).sum();
    }

    ...
}
----

If we need to interact with technical objects, we can place the lifecycle callback on a separate class, called an _entity listener_.
There are two distinct ways to attach listeners to an entity:

- The `@EntityListeners` annotation specifies one or more listeners for a given entity class:
+
[source,java]
----
@Entity
@EntityListeners(OrderEvents.class)
class Order { ... }
----

- On the other hand, the newer `@EntityListener` annotation lets a listener be attached to one or more entities without the need to annotate the entities themselves:
+
[source,java]
----
@EntityListener
class OrderEvents { ... }
----

An entity listener may inject CDI beans:

[source,java]
----
// entity listener class
class OrderEvents {
    @Inject
    Event<NewOrder> newOrderEvent;

    @PostPersist
    void newOrder(Order order) {
        // send a CDI event
        newOrderEvent.fire(new NewOrder(order));
    }
}
----
A single entity listener class may even be a generic listener that receives lifecycle callbacks for multiple different entity classes.

[TIP]
The venerable link:{doc-javadoc-url}org/hibernate/Interceptor.html[`Interceptor`] interface is a more powerful alternative to entity listeners.
`Interceptor` and its friend link:{doc-javadoc-url}org/hibernate/CustomEntityDirtinessStrategy.html[`CustomEntityDirtinessStrategy`] allow advanced users to augment the built-in handling of managed entities with custom behavior.
These interfaces are very useful if you're building your own persistence framework with Hibernate as the foundation.

We're about to see one way `Interceptor` can be used.

[[transient-vs-detached]]
=== Transient vs detached

Sometimes, Hibernate needs to be able to distinguish whether an entity instance is:

- a brand-new transient object the client just instantiated using `new`, or
- a detached object, which previously belonged to a persistence context.

This is a bit of a problem, since there's no good and efficient way for Hibernate to just tag an entity with a Post-it saying "I've seen you before".

Therefore, Hibernate uses heuristics.
The two most useful heuristics are:

1. If the entity has a <<generated-identifiers,generated identifier>>, the value of the id field is inspected: if the value currently assigned to the id field is the default value for the type of the field, then the object is transient; otherwise, the object is detached.
2. If the entity has a <<version-attributes,version>>, the value of the version field is inspected: if the value currently assigned to the version field is null or a negative number, then the object is transient; otherwise, the object is detached.

If the entity has neither a generated id, nor a version, Hibernate usually falls back to just doing something reasonable.
In extreme cases a `SELECT` query will be issued to determine whether a matching row exists in the database.

[WARNING]
These heuristics aren't perfect.
It's quite easy to confuse Hibernate by assigning a value to the id field or version field, making a new transient instance look like it's detached.
We therefore strongly discourage assigning values to fields annotated `@GeneratedValue` or `@Version` before passing an entity to Hibernate.

If the heuristics ever happen cause a real problem, you may implement your own Post-it tagging via link:{doc-javadoc-url}org/hibernate/Interceptor.html#isTransient(java.lang.Object)[`Interceptor.isTransient()`].


[[jdbc]]
=== Interacting directly with JDBC

From time to time we run into the need to write some code that calls JDBC directly.
The `EntityManager` now offers a convenient way to do this:

[source,java]
----
entityManager.runWithConnection((Connection connection) -> {
    try (var callable = connection.prepareCall("{call myproc(?)}")) {
        callable.setLong(1, argument);
        callable.execute();
    }
});
----

To return a value, use `callWithConnection()` instead of `runWithConnection()`.

// The Hibernate `Session` has an older, slightly simpler API:
//
// [source,java]
// ----
// entityManager.unwrap(Session.class).doWork(connection -> {
//     try (var callable = connection.prepareCall("{call myproc(?)}")) {
//         callable.setLong(1, argument);
//         callable.execute();
//     }
// });
// ----
//
// If the work returns a value, use `doReturningWork()` instead of `doWork()`.

The `Connection` passed to the work is the same connection being used by the session, and so any work performed using that connection occurs in the same transaction context.

[TIP]
====
In a container environment where transactions and database connections are managed by the container, this might not be the easiest way to obtain the JDBC connection.
====

[[advice]]
=== What to do when things go wrong

Object/relational mapping has been called the "Vietnam of computer science".
The person who made this analogy is American, and so one supposes that he meant to imply some kind of unwinnable war.
This is quite ironic, since at the very moment he made this comment, Hibernate was already on the brink of winning the war.

Today, Vietnam is a peaceful country with exploding per-capita GDP, and ORM is a solved problem.
That said, Hibernate is complex, and ORM still presents many pitfalls for the inexperienced, even occasionally for the experienced.
Sometimes things go wrong.

In this section we'll quickly sketch some general strategies for avoiding "quagmires".

- Understand SQL and the relational model.
  Know the capabilities of your RDBMS.
  Work closely with the DBA if you're lucky enough to have one.
  Hibernate is not about "transparent persistence" for Java objects.
  It's about making two excellent technologies work smoothly together.
- <<logging-generated-sql,Log the SQL>> executed by Hibernate.
  You cannot know that your persistence logic is correct until you've actually inspected the SQL that's being executed.
  Even when everything seems to be "working", there might be a lurking <<association-fetching,N+1 selects monster>>.
- Be careful when <<bidirectional-problem,modifying bidirectional associations>>.
  In principle, you should update _both ends_ of the association.
  But Hibernate doesn't strictly enforce that, since there are situations where such a rule would be too heavy-handed.
  Whatever the case, it's up to you to maintain consistency across your model.
- Never <<persistence-contexts,leak a persistence context>> across threads or concurrent transactions.
  Have a strategy or framework to guarantee this never happens.
- When running queries that return large result sets, take care to consider the size of the <<session-cache-management,session cache>>.
  Consider using a <<stateless-sessions,stateless session>>.
- Think carefully about the semantics of the <<second-level-cache,second-level cache>>, and how the caching policies impact transaction isolation.
- Avoid fancy bells and whistles you don't need.
  Hibernate is incredibly feature-rich, and that's a good thing, because it serves the needs of a huge number of users, many of whom have one or two very specialized needs.
  But nobody has _all_ those specialized needs.
  In all probability, you have none of them.
  Write your domain model in the simplest way that's reasonable, using the simplest mapping strategies that make sense.
- When something isn't behaving as you expect, _simplify_.
  Isolate the problem.
  Find the absolute minimum test case which reproduces the behavior, _before_ asking for help online.
  Most of the time, the mere act of isolating the problem will suggest an obvious solution.
- If you're new to Hibernate, avoid frameworks and libraries that "wrap" JPA.
  You need an excellent understanding of Hibernate and JPA _first_, before introducing unnecessary additional moving parts.
  If there's any one criticism of Hibernate and ORM that sometimes _does_ ring true, it's that it takes you too far from direct control over JDBC.
  An additional layer just takes you even further.
  If you insist you really do need this extra layer, we beg you to consider https://hibernate.org/repositories/[Hibernate Data Repositories] instead of older third-party solutions.
- Avoid copy/pasting code from random bloggers or stackoverflow reply guys.
  Many of the suggestions you'll find online just aren't the simplest solution, and many aren't correct for Hibernate 6 and 7.
  Instead, _understand_ what you're doing; study the Javadoc of the APIs you're using; read the JPA specification; follow the advice we give in this document; go direct to the Hibernate team on Zulip.
  (Sure, we can be a bit cantankerous at times, but we _do_ always want you to be successful.)
- Always consider other options.
  You don't have to use Hibernate for _everything_.

---

### Documentation Src Main Asciidoc Introduction Introduction (`documentation/src/main/asciidoc/introduction/Introduction.adoc`)

[[introduction]]
== Introduction

:persistence: https://jakarta.ee/specifications/persistence/4.0/jakarta-persistence-spec-4.0-M4.pdf
:data: https://jakarta.ee/specifications/data/1.1/jakarta-data-1.1-m3.pdf
:query: https://jakarta.ee/specifications/query/1.0/jakarta-query-1.0-m2.pdf

Hibernate is usually described as a library that makes it easy to map Java classes to relational database tables.
But this formulation does no justice to the central role played by the relational data itself.
So a better description might be:

****
Hibernate makes *relational data* visible to a program written in Java, in a *natural* and *typesafe* form,

1. making it easy to write complex queries and work with their results,
2. letting the program easily synchronize changes made in memory with the database, respecting the ACID properties of transactions,
3. automatically handling concerns like temporal data, audit logging, multi-tenancy, and row-level security, and
4. allowing performance optimizations to be made after the basic persistence logic has already been written.
****

Here the relational data is the focus, along with the importance of type safety.
The goal of _object/relational mapping_ (ORM) is to eliminate fragile and untypesafe code, and make large programs easier to maintain in the long run.

ORM takes the pain out of persistence by relieving the developer of the need to hand-write tedious, repetitive, and fragile code for flattening graphs of objects to database tables and rebuilding graphs of objects from flat SQL query result sets.
Even better, ORM makes it much easier to tune performance later, after the basic persistence logic has already been written.

Actually, the problem that object/relational mapping solves has been mischaracterized for decades, and has very little to do with any so-called "mismatch" between classes and tables. The real problem is:

1. Data is stored in **normalized tables**.
2. The process of efficiently reading data from tables **<<join-fetch,denormalizes the data with joins>>**.
3. In an object-oriented program, we often want to work with data in something quite close to its **original normalized form**.

Therefore, the principal task of object/relational mapping is to _renormalize the data after reading it from the database_. This need exists even if the classes in our program are identical to the database tables.

[[orm-or-sql]]
[TIP]
// .ORM or SQL?
====
A perennial question is: should I use ORM, or plain SQL?
The answer is usually: _use both_.
JPA and Hibernate were designed to work _in conjunction with_ handwritten SQL.
You see, most programs with nontrivial data access logic will benefit from the use of ORM at least _somewhere_.
But if Hibernate is making things more difficult, for some particularly tricky piece of data access logic, the only sensible thing to do is to use something better suited to the problem!
Just because you're using Hibernate for persistence doesn't mean you have to use it for _everything_.
====

Let's underline the important point here: the goal of ORM is _not_ to hide SQL or the relational model.
After all, Hibernate's query language is link:{doc-query-language-url}[nothing more than an object-oriented dialect of ANSI SQL].
On the other hand, Hibernate does help smooth over many of the differences between relational databases and SQL dialects.

.*Read more: Is Hibernate a leaky abstraction?*
[%collapsible]
====
****
Hibernate--and ORM in general--has been accused of being a _leaky abstraction_, that is, of failing to completely hide the underlying relational database.
Is this true?

Well, as you can guess from what we've already said, the short answer is: yes, _and that's a good thing._

Of course, whether you consider an abstraction "leaky" depends on what you think it's trying to abstract.
Hibernate successfully abstracts many things: variations between dialects of SQL, messy interactions with JDBC, SQL object naming conventions, and so on.
But it doesn't even attempt to pretend there's anything other than a relational data model underlying all this.
The simple reason is performance. It's just not possible to <<tuning-and-performance,achieve acceptable performance>> in data access without acknowledging the nature of the underlying persistent representation.
We're old enough to have seen multiple generations of developer relearn this lesson by experience.
****
====

Developers often ask about the relationship between Hibernate and JPA, so let's bite that cookie first.

[[hibernate-and-jpa]]
=== Hibernate and JPA

Hibernate was the inspiration behind the _Java_ (now _Jakarta_) _Persistence API_, or JPA, and includes a complete implementation of the latest revision of link:{persistence}[this specification].
In recent years, the Hibernate team has led the efforts to modernize the Jakarta EE persistence specifications, culminating in the release of this three-headed hellhound: Persistence 4.0, Query 1.0, and Data 1.1.

[[history]]
.*Read more: The early history of Hibernate and JPA*
[%collapsible]
====
****
The Hibernate project began in 2001, when Gavin King's frustration with Entity Beans in EJB 2 boiled over.
It quickly overtook other open source and commercial contenders to become the most popular persistence solution for Java, and the book _Hibernate in Action_, written with Christian Bauer, was an influential bestseller.

In 2004, Gavin and Christian joined a tiny startup called JBoss, and other early Hibernate contributors soon followed: Max Rydahl Andersen, Emmanuel Bernard, Steve Ebersole, and Sanne Grinovero.

Soon after, Gavin joined the EJB 3 expert group and convinced the group to deprecate Entity Beans in favor of a brand-new persistence API modelled after Hibernate.
Later, members of the TopLink team got involved, and the Java Persistence API evolved as a collaboration between—primarily—Sun, JBoss, Oracle, and Sybase, under the leadership of Linda Demichiel.

Over the intervening two decades, _many_ talented people have contributed to the development of Hibernate.
We're all especially grateful to Steve, who has led the project for many years, since Gavin stepped back to focus on other work.
****
====

We can think of Hibernate in terms of four basic elements:

- an implementation of the JPA-defined APIs, most importantly, of the interfaces `EntityManagerFactory`, `EntityAgent`, and `EntityManager`, and of the JPA-defined O/R mapping annotations,
- a _native API_ exposing the full set of available functionality, centered around the interfaces link:{doc-javadoc-url}org/hibernate/SessionFactory.html[`SessionFactory`], which extends `EntityManagerFactory`,
link:{doc-javadoc-url}org/hibernate/StatelessSession.html[`StatelessSession`], which extends `EntityAgent`, and link:{doc-javadoc-url}org/hibernate/Session.html[`Session`], which extends `EntityManager`,
- a set of link:{doc-javadoc-url}org/hibernate/annotations/package-summary.html[_mapping annotations_] which augment the O/R mapping annotations defined by JPA, and which may be used with the JPA-defined interfaces, or with the native API, and
- finally, <<metamodel-generator,Hibernate Processor>>, which is responsible for generating the _static metamodel_ and implementations of Jakarta Data repositories.

Hibernate also offers a range of SPIs for frameworks and libraries which extend or integrate with Hibernate, but we're not interested in any of that stuff here.

image::images/api-overview.png[API overview,width=700,align="center"]

Before JPA 4, many teams chose to write their program in terms of `Session` and `SessionFactory`, to take advantage of the larger feature set accessible via these APIs.
Other teams chose to maximize portability to other implementations of JPA by, wherever reasonable, writing code in terms of  `EntityManager` and `EntityManagerFactory`, falling back to the native APIs only where necessary.
JPA 4 tips the balance quite far in favor of the standard JPA APIs.

[IMPORTANT]
As of Jakarta Persistence 4.0, we feel that there's no longer much advantage to be had from the direct use of `Session` and `SessionFactory`, at least not most of the time.
New code can be written in terms of the standard `EntityManager` and `EntityManagerFactory` interfaces, and a broad range of Hibernate-specific extensions are made available as JPA _option objects_.

Whichever path you take, you will use the JPA-defined mapping annotations most of the time, and the Hibernate-defined annotations for more advanced mapping problems.

You might wonder if it's possible to develop an application using _only_ JPA-defined APIs, and, indeed, that's possible in principle.
JPA is a great baseline that really nails the basics of the object/relational mapping problem.
But without the extended mapping annotations, and without the occasional use of Hibernate-specific option objects, you miss out on much of the power of Hibernate.

Since Hibernate existed before JPA, and since JPA was modelled on Hibernate, we unfortunately have some competition and duplication in naming between the standard and native APIs.
For example:

.Examples of competing APIs with similar naming
|===
| Hibernate | JPA

| `org.hibernate.FlushMode` | `javax.persistence.FlushModeType`
| `org.hibernate.annotations.FetchMode` | `javax.persistence.FetchType`
| `@org.hibernate.annotations.Fetch` | `@jakarta.persistence.Fetch`
| `org.hibernate.query.Query` | `javax.persistence.Query`
| `org.hibernate.Cache` | `javax.persistence.Cache`
| `@org.hibernate.annotations.NamedQuery` | `@javax.persistence.NamedQuery`
| `@org.hibernate.annotations.Cache` | `@javax.persistence.Cacheable`
| `org.hibernate.relational.SchemaManager` | `jakarta.persistence.SchemaManager`
|===

Typically, the Hibernate-native APIs offer something a little extra that's missing in JPA, so this isn't exactly a _flaw_.
But it's something to watch out for.

[[hello-hibernate]]
=== Hello, Hibernate

Before we get deeper into the weeds, we'll quickly present a basic example program that will help you get started if you don't already have Hibernate integrated into your project.

We begin with a simple https://gradle.org[Gradle] build file:

[[build-gradle]]
[source,groovy,subs="attributes+"]
.`build.gradle`
----
plugins {
    id 'java'
}

group = 'org.example'
version = '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    // the GOAT ORM (required)
    implementation 'org.hibernate.orm:hibernate-core:{fullVersion}'

    // Hibernate Processor (strongly recommended)
    annotationProcessor 'org.hibernate.orm:hibernate-processor:{fullVersion}'

    // Jakarta Data support (optional)
    implementation 'jakarta.data:jakarta.data-api:1.1.0-M4'
    implementation 'jakarta.data:jakarta.data.stateful-api:1.1.0-M4'

    // Hibernate Validator (optional)
    implementation 'org.hibernate.validator:hibernate-validator:9.0.1.Final'
    implementation 'org.glassfish.expressly:expressly:6.0.0'

    // Agroal connection pool (optional)
    runtimeOnly 'org.hibernate.orm:hibernate-agroal:{fullVersion}'

    // logging via Log4j (recommended)
    runtimeOnly 'org.apache.logging.log4j:log4j-core:2.26.0'

    // H2 database (or JDBC driver of choice)
    runtimeOnly 'com.h2database:h2:2.4.240'
}
----

Only the first of these dependencies is absolutely _required_ to run Hibernate.

Next, we'll add a logging configuration file for https://logging.apache.org/log4j/[log4j]:

[source,properties]
.`log4j2.properties`
----
rootLogger.level = info
rootLogger.appenderRefs = console
rootLogger.appenderRef.console.ref = console

# SQL statements (set level=debug to enable)
logger.hibernate.name = org.hibernate.SQL
logger.hibernate.level = info
# JDBC parameter binding (set level=trace to enable)
logger.jdbc-bind.name=org.hibernate.orm.jdbc.bind
logger.jdbc-bind.level=info
# JDBC result set extraction (set level=trace to enable)
logger.jdbc-extract.name=org.hibernate.orm.jdbc.extract
logger.jdbc-extract.level=info
# JDBC batching (set level=trace to enable)
logger.batch.name=org.hibernate.orm.jdbc.batch
logger.batch.level=info

# direct log output to the console
appender.console.name = console
appender.console.type = Console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %highlight{[%p]} %m%n
----

Now we need some Java code.
We begin with our <<domain-model,_entity class_>>:

[[book]]
[source,java]
.`Book.java`
----
package org.hibernate.example;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.validation.constraints.NotNull;

@Entity
public class Book {
    @Id
    String isbn;

    @NotNull
    String title;

    Book() {}

    public Book(String isbn, String title) {
        this.isbn = isbn;
        this.title = title;
    }
}
----

Finally, let's see code which <<configuration,configures>> and instantiates Hibernate and asks it to <<interacting,persist and query>> the entity.
Don't worry if this makes no sense at all right now.
It's the job of the rest of this guide to make all this crystal clear as we go along.

[[main-hibernate]]
[source,java]
.`Main.java`
----
import org.hibernate.example.*;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.FetchType;
import jakarta.persistence.PersistenceConfiguration;

import static java.lang.System.out;
import static jakarta.persistence.SchemaManagementAction.CREATE;
import static jakarta.persistence.PersistenceConfiguration.*;
import static org.hibernate.cfg.JdbcSettings.*;

EntityManagerFactory factory =
        new PersistenceConfiguration("Bookshelf")
                // all associations should be lazy by default
                .defaultToOneFetchType(FetchType.LAZY)
                // register the entity class
                .managedClass(Book.class)
                // use H2 in-memory database
                .property(JDBC_URL, "jdbc:h2:mem:db1")
                .property(JDBC_USER, "sa")
                .property(JDBC_PASSWORD, "")
                // set the Agroal connection pool size
                .property(POOL_SIZE, 16)
                // display SQL in console
                .property(SHOW_SQL, true)
                .property(FORMAT_SQL, true)
                .property(HIGHLIGHT_SQL, true)
                // export the inferred database schema
                .schemaManagementDatabaseAction(CREATE)
                // start Hibernate
                .createEntityManagerFactory();

void main() {
    // persist an entity
    factory.runInTransaction(manager -> {
        manager.persist(new Book("9781932394153", "Hibernate in Action"));
    });

    // query data using HQL
    factory.runInTransaction(manager -> {
        manager.createQuery("select isbn || ': ' || title from Book")
                .ofType(String.class)
                .getResultList()
                .forEach(out::println);
    });

    // query data using criteria API
    factory.runInTransaction(manager -> {
        var builder = factory.getCriteriaBuilder();
        var query = builder.createQuery(String.class);
        var book = query.from(Book.class);
        query.select(builder.concat(
                List.of(book.get(Book_.isbn),
                        builder.literal(": "),
                        book.get(Book_.title))));
        manager.createQuery(query)
                .getResultList()
                .forEach(out::println);
    });
}
----

This code introduces two very central interfaces:

- the `EntityManagerFactory`, which in Hibernate is also an instance of link:{doc-javadoc-url}org/hibernate/SessionFactory.html[`SessionFactory`], and
- a mysterious `manager` object, which in JPA an instance of `EntityManager`, and in Hibernate is also an instance of link:{doc-javadoc-url}org/hibernate/Session.html[`Session`].

In this guide, we call each instance of `EntityManager` a _session_.

In practice, we never access the database directly from a `main()` method.
// So now let's now return to the question of how to organize persistence logic in a real system.

[[java-code]]
=== Writing Java code with Hibernate

If you're completely new to Hibernate and JPA, you might already be wondering how the persistence-related code is structured.

Well, typically, our persistence-related code comes in two layers:

. a representation of our data model in Java, which takes the form of a set of annotated entity classes, and
. a larger number of functions which interact with Hibernate's APIs to perform the persistence operations associated with our various transactions.

The first part, the data or "domain" model, is usually easier to write, but doing a great and very clean job of it will strongly affect your success in the second part.

Most people implement the domain model as a set of what we used to call "Plain Old Java Objects", that is, as simple Java classes with no direct dependencies on technical infrastructure, nor on application logic which deals with request processing, transaction management, communications, or interaction with the database.

[TIP]
====
Take your time with this code, and try to produce a Java model that's as close as reasonable to the relational data model. Avoid using exotic or advanced mapping features when they're not really needed.
When in the slightest doubt, map a foreign key relationship using `@ManyToOne` with `@OneToMany(mappedBy=...)` in preference to more complicated association mappings.
====

The second part of the code is much trickier to get right. This code must:

- manage transactions and sessions,
- interact with the database via the Hibernate session,
- publish CDI events and send JMS messages,
- fetch and prepare data needed by the UI, and
- handle failures.

[TIP]
====
Responsibility for transaction and session management, and for recovery from certain kinds of failure, is best handled in some sort of framework code.
====

// [TIP]
// ====
// A great way to handle CDI event publication is via a <<callbacks,JPA entity listener>>.
// Whereas we would never want to inject a CDI https://jakarta.ee/specifications/cdi/3.0/apidocs/[event publisher] into an entity object, it's perfectly fine to inject them in an entity listener.
// ====

We're going to <<organizing-persistence,come back soon>> and describe one good way to organize persistence logic, but we will emphasize that it's not the only way.
First, let's talk about entities.

[[domain-model]]
=== Entities

A class in the domain model which directly represents a relational database table is called an <<entities,_entity_>>.
Entity classes are central to object persistence and to object/relational mapping.
They're also, typically, central players in the business logic of our application program.
Entities represent the _things_ in our business domain.
This makes them very important objects indeed!

Given how much weight an entity already bears due to its very nature, we need to think carefully before weighing it down with too many additional responsibilities.

[[entity-logic]]
.*Read more: Rich and anemic entities*
[%collapsible]
====
****
There exists an extensive online literature which posits that there are _rich domain models_, where entities have methods implementing interesting business logic, and _anemic domain models_, where the entities are pure data holders, and that a developer should hold an opinion that one or the other of these sorts of domain model is "better".

We do not hold any such opinion, and if you ask us for one, we will most likely suddenly discover somewhere else we need to be.

A more interesting question is not _how much_ logic belongs in the entity class, but _what sort_ of logic belongs there.
****
====

We think that an entity should never implement technical concerns, and should never obtain references to framework objects.
Nor should it hold extra mutable state which is not very directly related to its role in representing persistent state.
For example:

- an entity may compute totals and averages, even caching them if necessary, enforce its invariants, interact with and construct other entities, and so on, and its annotations express how it maps to database tables,
- but the entity should not call the `EntityManager` or a Jakarta Data repository, build a criteria query, send a JMS message, start a transaction, publish events to the CDI event bus, maintain a stateful queue of events to be published later, or anything of a similar nature.

One way to summarize this is:

> Entities do business logic; but they don't do orchestration.

Later, we'll discuss various ways to <<managing-transactions,manage transactions>>, <<callbacks,send event notifications>>, and <<organizing-persistence,query the database>>.
Such code will always be external to the entity itself.

[[active-record]]
.*Read more: Active Record*
[%collapsible]
====
****
The discussion above expresses our "traditional" approach--which lay behind the design of Hibernate, of JPA, and of Jakarta Data--where entity classes are plain Java objects without dependence on framework code.
An alternative approach is the Active Record pattern, as exemplified by link:https://quarkus.io/guides/hibernate-orm-panache[Panache].
In Active Record, entity types inherit framework objects, and persistence operations are located directly on the entities.
You can think of this as merging the roles of entity and DAO/Repository into a single object.

Active Record comes with both upsides and downsides, but we don't mean to exclude it from consideration.
We must therefore slightly modify the prescription we've given above: in an Active Record, it's obviously OK to access the `EntityManager` and perform other persistence-related operations, and we therefore expect our Active Record class to look somewhat more "technical" than a trad entity.

But the basic principle remains intact: an entity does not do orchestration, it does not manage transactions, it does not obtain references to _other_ sorts of framework object, and it does not hold mutable state unrelated to its persistent state.
****
====

From now on, we're going to assume that entities are implemented as plain Java classes.

An entity can't persist itself.
For that we need a session.

[[stateful-and-stateless-sessions]]
=== Stateful and stateless sessions

It should be very clear from the example code <<main-hibernate,above>>, that the session is also a very important object.
It exposes basic operations like `persist()` and `createQuery()`, and so it's our first port of call when we want to <<interacting,interact with the database>> via Hibernate.
In the code we just saw, we've used a _stateful session_.

Later, we'll learn about the idea of a <<persistence-contexts,_persistence context_>>.
Oversimplifying for now, you can think of it as a cache of data which has been read in the current transaction.
Thus, in the architecture of Hibernate, it's sometimes called the _first-level cache_.
Each stateful session -- that is, every JPA <<hibernate-and-jpa,`EntityManager`>> -- has its own persistence context.

But stateful sessions are not the only possibility.
The new JPA 4 `EntityAgent` interface offers a way to interact with Hibernate _without_ going through a persistence context.
In Hibernate, every `EntityAgent` is also an instance of the much older interface <<stateless-sessions,`StatelessSession`>>, and so we often call an instance of `EntityAgent` a _stateless session_.
The programming model for stateless sessions is somewhat different.

.*Read more: Stateless sessions*
[%collapsible]
====
****
Among our biggest regrets is that we didn't give enough love to `StatelessSession` twenty years ago.
Sure, a stateful session is in some sense more powerful, or at least more magical.
But with that magic comes a loss of direct control over persistence operations, and some traps for inexperienced users.
A significant minority of developers find working with a persistence context frustrating, and they would surely be better served by a stateless session.

// - We used to view `StatelessSession` as an API directed toward very specific usage patterns, in particular, batch processing of large numbers of entities.
// As a result, we left out certain functionality -- for example, use of the <<second-level-cache,second-level cache>> -- which didn't seem relevant to those use cases.
// This left `StatelessSession` lacking feature parity with `Session`, and it was a mistake.
// In Hibernate 7, we've fixed this mistake.
// A `StatelessSession` now offers essentially all the functionality of Hibernate except, naturally, the first-level cache.
//
// - Compounding our error, we left `StatelessSession` out of JPA.
// This meant that a large number of Hibernate users _didn't even realize this option existed._
// We promise to make sure there are stateless sessions in Jakarta Persistence 4.

So, finally, let us state for the record: we messed up here.
Hibernate is all about _object/relational mapping;_ persistence contexts are something extra.
They're like the salsa verde in a Mexican dish--delicious, but optional--not like the green curry in a bowl of kaeng khiao wan.
You don't have to use stateful sessions, and you're not doing anything wrong if you decide to use stateless sessions instead.
****
====

A key decision for any new project is which of these programming models to take as a baseline.
Fortunately, the two models aren't mutually exclusive.
This is a friendly competition, where the two APIs are designed to complement each other.
Even if we decide to use stateful ``EntityManager``s most of the time, we can still use an `EntityAgent` wherever it's more convenient.

=== Managing sessions and transactions

One very nice aspect of the code we <<main-hibernate,just saw>>, which we wish to draw your attention to, is that session and transaction management is handled by generic "framework" code, just as we already recommended above.

Later, we'll discuss the traps we can fall into when we write custom code to manage <<persistence-contexts,sessions>> and <<managing-transactions,transactions>>.
It's certainly not impossible to get these concerns right, but it's easy enough to get them wrong, especially if we starting getting too creative.
Since we know that you, dear reader, are nothing if not creative, we encourage you to let your container or framework take care of this stuff.

In our code, we used the <<managing-transactions,`runInTransaction()`>> method of `EntityManagerFactor`.
But you might prefer to use something else, for example:

- in a container environment like Jakarta EE or https://quarkus.io[Quarkus]https://xxx[,] _container-managed transactions_ and _container-managed persistence contexts_, or
- something you write yourself.

The important thing is that calls like `createEntityManager()` and `getTransaction().begin()` don't belong in regular program logic, because it's tricky and tedious to get the error handling correct.

[[organizing-persistence]]
=== Repositories

In a real program, persistence logic like the code shown above is usually interleaved with other sorts of code, including logic:

- implementing the rules of the business domain, or
- for interacting with the user.

Therefore, many developers quickly--even _too quickly_, in our opinion--reach for ways to isolate the persistence logic into some sort of separate architectural layer.
For decades, there was no clearly "best" way to implement a persistence layer based on Hibernate, and frameworks which intended to simplify life for the developer seemed to us to actually make things worse.
With link:{data}[Jakarta Data 1.1], as implemented by <<generator,Hibernate Processor>>, the situation has changed, and the easiest way to write a persistence layer is now very clear.

.*Read more: Why we changed our mind about repositories*
[%collapsible]
====
****
At the time we wrote _An Introduction to Hibernate 6_, we were frustrated with the limitations of popular frameworks which claimed to simplify the use of JPA by wrapping and hiding the `EntityManager`.
In our considered opinion, such frameworks typically made JPA harder to use, sometimes misleading users into misuse of the technology.

The birth of the Jakarta Data specification has obsoleted our arguments against repositories, along with the older frameworks which were the source of our frustration.
Jakarta Data--as realized by Hibernate Data Repositories--offers a clean but very flexible way to organize code, along with much better compile-time type safety, without getting in the way of direct use of the `EntityAgent` or `EntityManager`.

Unlike other repository frameworks, Hibernate Data Repositories offers something that plain JPA simply doesn’t have: full compile-time type safety for your queries. To learn more, please refer to link:{doc-data-repositories-url}[Introducing Hibernate Data Repositories].
****
====

For now, let's see how we could rewrite our <<main-hibernate,earlier code>> using a repository.

[[repository-hibernate]]
[source,java]
.`Library.java`
----
package org.hibernate.example;

import jakarta.data.repository.Query;
import jakarta.data.repository.Repository;
import jakarta.persistence.EntityAgent;

import java.util.List;

@Repository
public interface Library {
    // access to the underlying stateful session
    EntityManager manager();

    // persist a book via the session
    @Persist
    void persist(Book entity);

    // a query method with a generated implementation
    // the query is fully validated at compile time!
    @Query("select isbn || ': ' || title from Book")
    List<String> summaries();

    // a repository method implemented by hand
    default List<String> summariesByCriteria() {
        var builder = manager().getCriteriaBuilder();
        var query = builder.createQuery(String.class);
        var book = query.from(Book.class);
        query.select(builder.concat(
                List.of(book.get(Book_.isbn),
                        builder.literal(": "),
                        book.get(Book_.title))));
        return manager().createQuery(query)
                .getResultList();
    }
}
----

Notice that the `@Repository` programming model lets us freely choose between:

- implementing a repository method by hand, and calling the `EntityManager` or `EntityAgent` directly, or
- having the implementation generated for us.

We could simplify our <<main-hibernate,`main()`>> method as follows:

[source,java]
.`Main.java`
----
...

EntityManagerFactory factory =
        new PersistenceConfiguration("Bookshelf")
                // all associations should be lazy by default
                .defaultToOneFetchType(FetchType.LAZY)
                // register the entity class
                .managedClass(Book.class)
                // register the repository interface!
                .managedClass(Library.class)
                // use H2 in-memory database
                .property(JDBC_URL, "jdbc:h2:mem:db1")
                .property(JDBC_USER, "sa")
                .property(JDBC_PASSWORD, "")
                // set the Agroal connection pool size
                .property(POOL_SIZE, 16)
                // display SQL in console
                .property(SHOW_SQL, true)
                .property(FORMAT_SQL, true)
                .property(HIGHLIGHT_SQL, true)
                // export the inferred database schema
                .schemaManagementDatabaseAction(CREATE)
                // start Hibernate
                .createEntityManagerFactory();

void main() {
    // persist an entity
    factory.runInTransaction(manager -> {
        Library library = new _Library(manager);
        library.persist(new Book("9781932394153", "Hibernate in Action"));
    });

    // query data using HQL
    factory.runInTransaction(manager -> {
        Library library = new _Library(manager);
        library.summaries().forEach(out::println);
    });

    // query data using criteria API
    factory.runInTransaction(manager -> {
        Library library = new _Library(manager);
        library.summariesByCriteria().forEach(out::println);
    });
}
----

In a real system we would not directly instantiate the generated `_Library` repository implementation class.
Instead, we would obtain the `Library` via dependency injection.
In Quarkus, WildFly, or any Jakarta EE container, https://www.cdi-spec.org[CDI] takes care of injecting repository objects.

[source,java]
@Inject Library library;

[IMPORTANT]
Notice that we registered the repository interface with the persistence unit via `managedClass()`.
// If we had used `persistence.xml` to configure Hibernate, we would have listed it as a `<class>`.

Now that we have a rough picture of what our persistence logic might look like, it's natural to ask how we should test our code.

[[testing]]
=== Testing persistence logic

:h2: http://www.h2database.com

When we write tests for our persistence logic, we're going to need:

1. a database, with
2. an instance of the schema mapped by our persistent entities, and
3. a set of test data, in a well-defined state at the beginning of each test.

It might seem obvious that we should test against the same database system that we're going to use in production, and, indeed, we should certainly have at least _some_ tests for this configuration.
But on the other hand, tests which perform I/O are much slower than tests which don't, and most databases can't be set up to run in-process.

So, since most persistence logic written using Hibernate 6 is _extremely_ portable between databases, it often makes good sense to test against an in-memory Java database.
({h2}[H2] is the one we recommend.)

[CAUTION]
====
We do need to be careful here if our persistence code uses native SQL, or if it uses concurrency-management features like pessimistic locks.
====

Whether we're testing against our real database, or against an in-memory Java database, we'll need to export the schema at the beginning of a test suite.
We _usually_ do this when we create the `EntityManagerFactory`, and so traditionally we've used a <<automatic-schema-export,configuration property>> for this.
The JPA-standard property is `jakarta.persistence.schema-generation.database.action`.

But if we're using `PersistenceConfiguration` to configure Hibernate, we could write:

[source,java]
----
configuration.schemaManagementDatabaseAction(SchemaManagementAction.DROP_AND_CREATE);
----

Alternatively, we may use the link:{doc-javadoc-url}org/hibernate/relational/SchemaManager.html[`SchemaManager`] API to export the schema.
This option is especially convenient when writing tests.

[source,java]
----
factory.getSchemaManager().create(true);
----

Since executing DDL statements is very slow on many databases, we don't want to do this before every test.
Instead, to ensure that each test begins with the test data in a well-defined state, we need to do two things before each test:

1. clean up any mess left behind by the previous test, and then
2. reinitialize the test data.

We may truncate all the tables, leaving an empty database schema, using the `SchemaManager`.

[source,java]
----
factory.getSchemaManager().truncate();
----

After truncating tables, we might need to initialize our test data.
We may specify test data in a SQL script, for example:

[[import.sql]]
[source,sql]
./import.sql
----
insert into Books (isbn, title) values ('9781932394153', 'Hibernate in Action')
insert into Books (isbn, title) values ('9781932394887', 'Java Persistence with Hibernate')
insert into Books (isbn, title) values ('9781617290459', 'Java Persistence with Hibernate, Second Edition')
----

If we name this file `import.sql`, and place it in the root classpath, that's all we need to do.

Otherwise, we need to specify the file in the <<automatic-schema-export,configuration property>> `jakarta.persistence.sql-load-script-source`.
If we're using `PersistenceConfiguration` to configure Hibernate, we could write:

[source,java]
----
configuration.property(PersistenceConfiguration.SCHEMAGEN_LOAD_SCRIPT_SOURCE,
                       "/org/example/test-data.sql");
----

The SQL script is executed every time `create()`, `populate()`, or `truncate()` is called.

[TIP]
====
There's another sort of mess a test can leave behind: cached data in the <<second-level-cache,second-level cache>>.
We recommend _disabling_ Hibernate's second-level cache for most sorts of testing.
Alternatively, if the second-level cache is not disabled, then before each test we should call:
[source,java]
----
factory.getCache()
        .unwrap(org.hibernate.Cache.class)
        .evictAllRegions();
----
====

Now, suppose you've followed our advice, and written your entities and query methods to minimize dependencies on "infrastructure", that is, on libraries other than JPA and Hibernate, on frameworks,  on container-managed objects, and even on bits of your own system which are hard to instantiate from scratch.
Then testing persistence logic is now straightforward!

You'll need to:

- bootstrap Hibernate and create a `EntityManagerFactory` at the beginning of your test suite (we've already seen how to do that), and
- create a new `EntityManager` or `EntityAgent` inside each `@Test` method, using `inTransaction()`, for example.

Actually, some tests might require multiple sessions.
But be careful not to leak a session between different tests.

[TIP]
=====
Another important test we'll need is one which validates our <<object-relational-mapping,O/R mapping annotations>> against the actual database schema.
This is again the job of the schema management tooling, either:
[source,java]
----
configuration.schemaManagementDatabaseAction(SchemaManagementAction.VALIDATE);
----
Or:
[source,java]
----
factory.getSchemaManager().validate();
----
This "test" is one which many people like to run even in production, when the system starts up.
=====

[[overview]]
=== Overview

It's now time to begin our journey toward actually _understanding_ the code we saw earlier.

This introduction will guide you through the basic tasks involved in developing a program that uses Hibernate for persistence:

1. configuring and bootstrapping Hibernate, and obtaining an instance of `EntityManagerFactory`,
2. writing a _domain model_, that is, a set of _entity classes_ which represent the persistent types in your program, and which map to tables of your database,
3. customizing these mappings when the model maps to a pre-existing relational schema,
4. using the `EntityManager` or `EntityAgent` to perform operations which query the database and return entity instances, or which update the data held in the database,
5. using Hibernate Processor to improve compile-time type-safety,
6. writing complex queries using the Hibernate Query Language (HQL) or native SQL, and, finally
7. tuning performance of the data access logic.

Naturally, we'll start at the top of this list, with the least-interesting topic: _configuration_.

---

### Documentation Src Main Asciidoc Introduction Mapping (`documentation/src/main/asciidoc/introduction/Mapping.adoc`)

[[object-relational-mapping]]
== Object/relational mapping

Given a domain model—that is, a collection of entity classes decorated with all the fancy annotations we <<entities-summary,just met>> in the previous chapter—Hibernate will happily go away and infer a complete relational schema, and even <<automatic-schema-export,export it to your database>> if you ask politely.

The resulting schema will be entirely sane and reasonable, though if you look closely, you'll find some flaws.
For example, by default, every `VARCHAR` column will have the same length, `VARCHAR(255)`.

But the process I just described—which we call _top down_ mapping—simply doesn't fit the most common scenario for the use of O/R mapping.
It's only rarely that the Java classes precede the relational schema.
Usually, _we already have a relational schema_, and we're constructing our domain model around the schema.
This is called _bottom up_ mapping.

[TIP]
// ."Legacy" data
====
Developers often refer to a pre-existing relational database as "legacy" data.
This tends to conjure images of bad old "legacy apps" written in COBOL or something.
But legacy data is valuable, and learning to work with it is important.
====

Especially when mapping bottom up, we often need to customize the inferred object/relational mappings.
This is a somewhat tedious topic, and so we don't want to spend too many words on it.
Instead, we'll quickly skim the most important mapping annotations.

[[case-convention]]
.*Read more: Hibernate SQL case convention*
[%collapsible]
====
****
Computers have had lowercase letters for rather a long time now.
Most developers learned long ago that text written in MixedCase, camelCase, or even snake_case is easier to read than text written in SHOUTYCASE.
This is just as true of SQL as it is of any other language.

Therefore, for over twenty years, the convention on the Hibernate project has been that:

- query language identifiers are written in `lowercase`,
- table names are written in `MixedCase`, and
- column names are written in `camelCase`.

That is to say, we simply adopted Java's excellent conventions and applied them to SQL.

Now, there's no way we can force you to follow this convention, even if we wished to.
Hell, you can easily write a `PhysicalNamingStrategy` which makes table and column names ALL UGLY AND SHOUTY LIKE THIS IF YOU PREFER.
But, _by default_, it's the convention Hibernate follows, and it's frankly a pretty reasonable one.
****
====

[[mapping-inheritance]]
=== Mapping entity inheritance hierarchies

In <<entity-inheritance>> we saw that entity classes may exist within an inheritance hierarchy.
There's three basic strategies for mapping an entity hierarchy to relational tables.
Let's put them in a table, so we can more easily compare the points of difference between them.

.Entity inheritance mapping strategies
|===
| Strategy | Mapping | Polymorphic queries | Constraints | Normalization | When to use it

| `SINGLE_TABLE`
| Map every class in the hierarchy to the same table, and uses the value of a _discriminator column_ to determine which concrete class each row represents.
| To retrieve instances of a given class, we only need to query the one table.
| Attributes declared by subclasses map to columns without `NOT NULL` constraints, and so their non-nullability is enforced via a `CHECK` constraint.

  Any association may have a `FOREIGN KEY` constraint. 🤓
| Subclass data is denormalized. 🧐
| Works well when subclasses declare few or no additional attributes.
| `JOINED`
| Map every class in the hierarchy to a separate table, but each table only maps the attributes declared by the class itself.

  Optionally, a discriminator column may be used.
a| To retrieve instances of a given class, we must `JOIN` the table mapped by the class with:

  - all tables mapped by its superclasses and
  - all tables mapped by its subclasses.
| Any attribute may map to a column with a `NOT NULL` constraint. 🤓

  Any association may have a `FOREIGN KEY` constraint. 🤓
| The tables are normalized. 🤓
| The best option when we care a lot about constraints and normalization.
| `TABLE_PER_CLASS`
| Map every concrete class in the hierarchy to a separate table, but denormalize all inherited attributes into the table.
| To retrieve instances of a given class, we must take a `UNION` over the table mapped by the class and the tables mapped by its subclasses.
| Associations targeting a superclass cannot have a corresponding `FOREIGN KEY` constraint in the database. 💀💀

  Any attribute may map to a column with a `NOT NULL` constraint. 🤓
| Superclass data is denormalized. 🧐
| Not very popular.

  From a certain point of view, competes with `@MappedSuperclass`.
|===

The three mapping strategies are enumerated by `InheritanceType`.
We specify an inheritance mapping strategy using the `@Inheritance` annotation.

For mappings with a _discriminator column_, we should:

- specify the discriminator column name and type by annotating the root entity `@DiscriminatorColumn`, and
- specify the values of this discriminator by annotating each entity in the hierarchy `@DiscriminatorValue`.

// [[single-table-inheritance]]
// === Single table inheritance

For single table inheritance we always need a discriminator:

[source,java]
----
@Entity
@DiscriminatorColumn(discriminatorType=CHAR, name="kind")
@DiscriminatorValue('P')
class Person { ... }

@Entity
@DiscriminatorValue('A')
class Author { ... }
----

We don't need to explicitly specify `@Inheritance(strategy=SINGLE_TABLE)`, since that's the default.

// [[multiple-table-inheritance]]
// === Multiple table inheritance

For `JOINED` inheritance we don't need a discriminator:

[source,java]
----
@Entity
@Inheritance(strategy=JOINED)
class Person { ... }

@Entity
class Author { ... }
----

[TIP]
// .Discriminator columns for `JOINED` inheritance
====
However, we can add a discriminator column if we like, and in that case the generated SQL for polymorphic queries is slightly simpler.
====

Similarly, for `TABLE_PER_CLASS` inheritance we have:

[source,java]
----
@Entity
@Inheritance(strategy=TABLE_PER_CLASS)
class Person { ... }

@Entity
class Author { ... }
----

[NOTE]
// .Discriminator columns for `TABLE_PER_CLASS` inheritance
====
Hibernate doesn't allow discriminator columns for `TABLE_PER_CLASS` inheritance mappings, since they would make no sense, and offer no advantage.
====

Notice that in this last case, a polymorphic association like:

[source,java]
----
@ManyToOne Person person;
----

is a bad idea, since it's impossible to create a foreign key constraint that targets both mapped tables.

// [[mixing-inheritance]]
// === Mixed inheritance
//
// Hibernate doesn't support mixing ``InheritanceType``s within a single entity hierarchy.
// However, it's possible to emulate a mix of `SINGLE_TABLE` and `JOINED` inheritance using the `@SecondaryTable` annotation.

[CAUTION]
====
It's quite easy to overuse inheritance.
We've occasionally seen extreme cases where a `JOINED` inheritance hierarchy includes _hundreds_ of entities, spanning hundreds of tables.
Efficiently querying such a hierarchy is an almost impossible task for Hibernate.
Fortunately, a `JOINED` inheritance relationship can always be remodeled as a <<one-to-one-pk,one-to-one association>>, allowing much more efficient queries.
In general, a single entity inheritance hierarchy should never span more than a few tables, including secondary tables.
====

[[table-mappings]]
=== Mapping to tables

The following annotations specify exactly how elements of the domain model map to tables of the relational model:

.Annotations for mapping tables
[%breakable,cols="25,~"]
|===
| Annotation | Purpose

| `@Table` | Map an entity class to its primary table
| `@SecondaryTable` | Define a secondary table for an entity class
| `@JoinTable` | Map a many-to-many or many-to-one association to its association table
| `@CollectionTable` | Map an `@ElementCollection` to its table
|===

The first two annotations are used to map an entity to its _primary table_ and, optionally, one or more _secondary tables_.

[[entity-table-mappings]]
=== Mapping entities to tables

By default, an entity maps to a single table, which may be specified using `@Table`:

[source,java]
----
@Entity
@Table(name="People")
class Person { ... }
----

However, the `@SecondaryTable` annotation allows us to spread its attributes across multiple _secondary tables_.

[source,java]
----
@Entity
@Table(name="Books")
@SecondaryTable(name="Editions")
class Book { ... }
----

The `@Table` annotation can do more than just specify a name:

.`@Table` annotation members
[%breakable,cols="20,~"]
|===
| Annotation member | Purpose

| `name` | The name of the mapped table
| `schema` 💀 | The schema to which the table belongs
| `catalog` 💀 | The catalog to which the table belongs
| `uniqueConstraints` | One or more `@UniqueConstraint` annotations declaring multi-column unique constraints
| `indexes` | One or more `@Index` annotations each declaring an index
| `check` | One or more `@CheckConstraint` annotations declaring multi-column check constraints
| `comment` | A DDL comment
|===

[%unbreakable]
[TIP]
// .If you don't need to, don't hardcode the schema and catalog
====
It only makes sense to explicitly specify the `schema` in annotations if the domain model is spread across multiple schemas.

Otherwise, it's a bad idea to hardcode the schema (or catalog) in a `@Table` annotation.
Instead:

- set the configuration property `hibernate.default_schema` (or `hibernate.default_catalog`), or
- simply specify the schema in the JDBC connection URL.
====

The `@SecondaryTable` annotation is even more interesting:

.`@SecondaryTable` annotation members
[%breakable,cols="20,~"]
|===
| Annotation member | Purpose

| `name` | The name of the mapped table
| `schema` 💀 | The schema to which the table belongs
| `catalog` 💀 | The catalog to which the table belongs
| `uniqueConstraints` | One or more `@UniqueConstraint` annotations declaring multi-column unique constraints
| `indexes` | One or more `@Index` annotations each declaring an index
| `pkJoinColumns` | One or more `@PrimaryKeyJoinColumn` annotations, specifying <<primary-key-column-mappings,primary key column mappings>>
| `foreignKey` | A `@ForeignKey` annotation specifying the name of the `FOREIGN KEY` constraint on the ``@PrimaryKeyJoinColumn``s
| `check` | One or more `@CheckConstraint` annotations declaring multi-column check constraints
| `comment` | A DDL comment
|===

[TIP]
====
Using `@SecondaryTable` on a subclass in a `SINGLE_TABLE` entity inheritance hierarchy gives us a sort of mix of `SINGLE_TABLE` with `JOINED` inheritance.
====

[[join-table-mappings]]
=== Mapping associations to tables

The `@JoinTable` annotation specifies an _association table_, that is, a table holding foreign keys of both associated entities.
This annotation is usually used with `@ManyToMany` associations:

[source,java]
----
@Entity
class Book {
    ...

    @ManyToMany
    @JoinTable(name="BooksAuthors")
    Set<Author> authors;

    ...
}
----

.*Show DDL*
[%collapsible%closed]
====
[source,sql]
create table BooksAuthors (
    Book_isbn varchar(255) not null,
    authors_ssn varchar(255) not null,
    primary key (Book_isbn, authors_ssn)
)
====

But it's even possible to use it to map a `@ManyToOne` or `@OneToOne` association to an association table.

[source,java]
----
@Entity
class Book {
    ...

    @ManyToOne(fetch=LAZY)
    @JoinTable(name="BookPublisher")
    Publisher publisher;

    ...
}
----

.*Show DDL*
[%collapsible%closed]
====
[source,sql]
create table BookPublisher (
    publisher_id bigint not null,
    isbn varchar(255) not null,
    primary key (isbn)
)
====

Here, there should be a `UNIQUE` constraint or `PRIMARY KEY` on one of the columns of the association table.

[source,java]
----
@Entity
class Author {
    ...

    @OneToOne(optional=false, fetch=LAZY)
    @JoinTable(name="AuthorPerson")
    Person author;

    ...
}
----

.*Show DDL*
[%collapsible%closed]
====
[source,sql]
create table AuthorPerson (
    author_ssn varchar(255) not null unique,
    ssn varchar(255) not null,
    primary key (ssn)
)
====

Here, there should be a `UNIQUE` constraint or `PRIMARY KEY` on _both_ columns of the association table.

Finally, `@JoinTable` may also be used with a <<unidirectional-one-to-many,unidirectional `@OneToMany` association>>.

[source,java]
----
@OneToMany // no matching @ManyToOne
@JoinTable(name="PublishedBooks")
Set<Book> books;
----

.*Show DDL*
[%collapsible%closed]
====
[source,sql]
create table PublishedBooks (
    Publisher_id bigint not null,
    books_isbn varchar(255) not null,
    primary key (books_isbn)
)
====

Here there is a `UNIQUE` or `PRIMARY KEY` constraint on the foreign key of the `Book` table in the join table `PublishedBooks`.

.`@JoinTable` annotation members
[%breakable,cols="20,~"]
|===
| Annotation member | Purpose

| `name` | The name of the mapped association table
| `schema` 💀 | The schema to which the table belongs
| `catalog` 💀 | The catalog to which the table belongs
| `uniqueConstraints` | One or more `@UniqueConstraint` annotations declaring multi-column unique constraints
| `indexes` | One or more `@Index` annotations each declaring an index
| `joinColumns` | One or more `@JoinColumn` annotations, specifying <<join-column-mappings,foreign key column mappings>> to the table of the owning side
| `inverseJoinColumns` | One or more `@JoinColumn` annotations, specifying <<join-column-mappings,foreign key column mappings>> to the table of the unowned side
| `foreignKey` | A `@ForeignKey` annotation specifying the name of the `FOREIGN KEY` constraint on the ``joinColumns``s
| `inverseForeignKey` | A `@ForeignKey` annotation specifying the name of the `FOREIGN KEY` constraint on the ``inverseJoinColumns``s
| `check` | One or more `@CheckConstraint` annotations declaring multi-column check constraints
| `comment` | A DDL comment
|===

To better understand these annotations, we must first discuss column mappings in general.

[[column-mappings]]
=== Mapping to columns

These annotations specify how elements of the domain model map to columns of tables in the relational model:

.Annotations for mapping columns
[%breakable,cols="25,~"]
|===
| Annotation | Purpose

| `@Column` | Map an attribute to a column
| `@JoinColumn` | Map an association to a foreign key column
| `@PrimaryKeyJoinColumn` | Map the primary key used to join a secondary table with its primary, or a subclass table in `JOINED` inheritance with its root class table
| `@OrderColumn` | Specifies a column that should be used to maintain the order of a `List`.
| `@MapKeyColumn` | Specified a column that should be used to persist the keys of a `Map`.
|===

We'll come back to the last two annotations much later, in <<ordered-sorted>>.

We use the `@Column` annotation to map basic attributes.

[[regular-column-mappings]]
=== Mapping basic attributes to columns

The `@Column` annotation is not only useful for specifying the column name.

.`@Column` annotation members
[%breakable,cols="20,~"]
|===
| Annotation member | Purpose

| `name` | The name of the mapped column
| `table` | The name of the table to which this column belongs
| `length` | The length of a `VARCHAR`, `CHAR`, or `VARBINARY` column type
| `precision` | The decimal digits of precision of a `FLOAT`, `DECIMAL`, or `NUMERIC` type
| `scale` | The scale of a `DECIMAL` or `NUMERIC` column type, the digits of precision that occur to the right of the decimal point
| `secondPrecision` | The digits of precision occurring to the right of the decimal point in the seconds field of a `TIME`, or `TIMESTAMP` column type
| `unique` | Whether the column has a `UNIQUE` constraint
| `nullable` | Whether the column has a `NOT NULL` constraint
| `insertable` | Whether the column should appear in generated SQL `INSERT` statements
| `updatable` | Whether the column should appear in generated SQL `UPDATE` statements
| `columnDefinition` 💀| A DDL fragment that should be used to declare the column
| `check` | One or more `@CheckConstraint` annotations declaring single-column check constraints
| `comment` | A DDL comment
|===

[TIP]
// .Use of `columnDefinition` results in unportable DDL
====
We no longer recommend the use of `columnDefinition` since it results in unportable DDL.
Hibernate has much better ways to customize the generated DDL using techniques that result in portable behavior across different databases.
====

Here we see four different ways to use the `@Column` annotation:

[source,java]
----
@Entity
@Table(name="Books")
@SecondaryTable(name="Editions",
        foreignKey = @ForeignKey(name="BooksToEditionsById"))
class Book {
    @Id @GeneratedValue
    @Column(name="bookId") // customize column name
    Long id;

    @Column(length=100, nullable=false) // declare column as VARCHAR(100) NOT NULL
    String title;
    
    @Column(length=17, unique=true, nullable=false) // declare column as VARCHAR(17) NOT NULL UNIQUE
    String isbn;
    
    @Column(table="Editions", updatable=false) // column belongs to the secondary table, and is never updated
    int edition;
}
----

.*Show DDL*
[%collapsible%closed]
====
[source,sql]
create table Books (
    bookId bigint not null,
    isbn varchar(17) not null unique,
    title varchar(100) not null,
    primary key (bookId)
)
create table Editions (
    edition integer,
    bookId bigint not null,
    primary key (bookId)
)
alter table if exists Editions
   add constraint BooksToEditionsById
   foreign key (bookId)
   references Books
====

Note that we have used the `@ForeignKey` annotation to assign a name to the foreign key constraint.

We don't use `@Column` to map associations.

[[join-column-mappings]]
=== Mapping associations to foreign key columns

The `@JoinColumn` annotation is used to customize a foreign key column.

.`@JoinColumn` annotation members
[%breakable,cols="20,~"]
|===
| Annotation member | Purpose

| `name` | The name of the mapped foreign key column
| `table` | The name of the table to which this column belongs
| `referencedColumnName` | The name of the column to which the mapped foreign key column refers
| `unique` | Whether the column has a `UNIQUE` constraint
| `nullable` | Whether the column has a `NOT NULL` constraint
| `insertable` | Whether the column should appear in generated SQL `INSERT` statements
| `updatable` | Whether the column should appear in generated SQL `UPDATE` statements
| `columnDefinition` 💀| A DDL fragment that should be used to declare the column
| `foreignKey` | A `@ForeignKey` annotation specifying the name of the `FOREIGN KEY` constraint
| `check` | One or more `@CheckConstraint` annotations declaring single-column check constraints
| `comment` | A DDL comment
|===

A foreign key column doesn't necessarily have to refer to the primary key of the referenced table.
It's quite acceptable for the foreign key to refer to any other unique key of the referenced entity, even to a unique key of a secondary table.

Here we see how to use `@JoinColumn` to define a `@ManyToOne` association mapping a foreign key column which refers to the `@NaturalId` of `Book`:

[source,java]
----
@Entity
@Table(name="Items")
class Item {
    ...

    @ManyToOne(optional=false)  // implies nullable=false
    @JoinColumn(name = "bookIsbn", referencedColumnName = "isbn",  // a reference to a non-PK column
                foreignKey = @ForeignKey(name="ItemsToBooksBySsn")) // supply a name for the FK constraint
    Book book;

    ...
}
----

.*Show DDL*
[%collapsible%closed]
====
[source,sql]
create table Items (
    id bigint not null,
    bookIsbn varchar(17) not null,
    primary key (id)
)
alter table if exists Items
   add constraint ItemsToBooksBySsn
   foreign key (bookIsbn)
   references Books (isbn)
====

In case this is confusing:

- `bookIsbn` is the name of the foreign key column in the `Items` table,
- it refers to a unique key `isbn` in the `Books` table, and
- it has a foreign key constraint named `ItemsToBooksBySsn`.

Note that the `foreignKey` member is completely optional and only affects DDL generation.

[TIP]
// .Foreign key constraint names
====
If you don't supply an explicit name using `@ForeignKey`, Hibernate will generate a quite ugly name.
The reason for this is that the maximum length of foreign key names on some databases is extremely constrained, and we need to avoid collisions.
To be fair, this is perfectly fine if you're only using the generated DDL for testing.
You can customize the generated constraint names by writing your own <<naming-strategies,`ImplicitNamingStrategy`>>.
====

For composite foreign keys we might have multiple `@JoinColumn` annotations:

[source,java]
----
@Entity
@Table(name="Items")
class Item {
    ...

    @ManyToOne(optional=false)
    @JoinColumn(name = "bookIsbn", referencedColumnName = "isbn")
    @JoinColumn(name = "bookPrinting", referencedColumnName = "printing")
    Book book;

    ...
}
----

If we need to specify the `@ForeignKey`, this starts to get a bit messy:

[source,java]
----
@Entity
@Table(name="Items")
class Item {
    ...

    @ManyToOne(optional=false)
    @JoinColumns(value = {@JoinColumn(name = "bookIsbn", referencedColumnName = "isbn"),
                          @JoinColumn(name = "bookPrinting", referencedColumnName = "printing")},
                 foreignKey = @ForeignKey(name="ItemsToBooksBySsn"))
    Book book;

    ...
}
----

For associations mapped to a `@JoinTable`, fetching the association requires two joins, and so we must declare the ``@JoinColumn``s inside the `@JoinTable` annotation:

[source,java]
----
@Entity
class Book {
    @Id @GeneratedValue
    Long id;

    @ManyToMany
    @JoinTable(joinColumns=@JoinColumn(name="bookId"),
               inverseJoinColumns=@joinColumn(name="authorId"),
               foreignKey=@ForeignKey(name="BooksToAuthors"))
    Set<Author> authors;

    ...
}
----

Again, the `foreignKey` member is optional.

[TIP]
====
For mapping a `@OneToOne` association <<one-to-one-pk,to a primary key>> with `@MapsId`, Hibernate lets us use either `@JoinColumn` or `@PrimaryKeyJoinColumn`.
[source,java]
----
@Entity
class Author {
    @Id
    Long id;

    @OneToOne(optional=false, fetch=LAZY)
    @MapsId
    @PrimaryKeyJoinColumn(name="personId")
    Person author;

    ...
}
----
Arguably, the use of `@PrimaryKeyJoinColumn` is clearer.
====

[[primary-key-column-mappings]]
=== Mapping primary key joins between tables

The `@PrimaryKeyJoinColumn` is a special-purpose annotation for mapping:

- the primary key column of a `@SecondaryTable`—which is also a foreign key referencing the primary table, or
- the primary key column of the primary table mapped by a subclass in a `JOINED` inheritance hierarchy—which is also a foreign key referencing the primary table mapped by the root entity.

.`@PrimaryKeyJoinColumn` annotation members
[%breakable,cols="20,~"]
|===
| Annotation member | Purpose

| `name` | The name of the mapped foreign key column
| `referencedColumnName` | The name of the column to which the mapped foreign key column refers
| `columnDefinition` 💀| A DDL fragment that should be used to declare the column
| `foreignKey` | A `@ForeignKey` annotation specifying the name of the `FOREIGN KEY` constraint
|===

When mapping a subclass table primary key, we place the `@PrimaryKeyJoinColumn` annotation on the entity class:

[source,java]
----
@Entity
@Table(name="People")
@Inheritance(strategy=JOINED)
class Person { ... }

@Entity
@Table(name="Authors")
@PrimaryKeyJoinColumn(name="personId") // the primary key of the Authors table
class Author { ... }
----

But to map a secondary table primary key, the `@PrimaryKeyJoinColumn` annotation must occur inside the `@SecondaryTable` annotation:

[source,java]
----
@Entity
@Table(name="Books")
@SecondaryTable(name="Editions",
                pkJoinColumns = @PrimaryKeyJoinColumn(name="bookId")) // the primary key of the Editions table
class Book {
    @Id @GeneratedValue
    @Column(name="bookId") // the name of the primary key of the Books table
    Long id;

    ...
}
----

[[column-lengths]]
=== Column lengths and adaptive column types

Hibernate automatically adjusts the column type used in generated DDL based on the column length specified by the `@Column` annotation.
So we don't usually need to explicitly specify that a column should be of type `TEXT` or `CLOB`—or worry about the parade of `TINYTEXT`, `MEDIUMTEXT`, `TEXT`, `LONGTEXT` types on MySQL—because Hibernate automatically selects one of those types if required to accommodate a string of the `length` we specify.

The constant values defined in the class link:{doc-javadoc-url}org/hibernate/Length.html[`Length`] are very helpful here:

.Predefined column lengths
[%breakable,cols="10,12,~"]
|===
| Constant | Value | Description

| `DEFAULT` | 255 | The default length of a `VARCHAR` or `VARBINARY` column when none is explicitly specified
| `LONG` | 32600 | The largest column length for a `VARCHAR` or `VARBINARY` that is allowed on every database Hibernate supports
| `LONG16` | 32767 | The maximum length that can be represented using 16 bits (but this length is too large for a `VARCHAR` or `VARBINARY` column on for some database)
| `LONG32` | 2147483647 | The maximum length for a Java string
|===

We can use these constants in the `@Column` annotation:

[source,java]
----
@Column(length=LONG)
String text;

@Column(length=LONG32)
byte[] binaryData;
----

This is usually all you need to do to make use of large object types in Hibernate.

[[lobs]]
=== LOBs

JPA provides a `@Lob` annotation which specifies that a field should be persisted as a `BLOB` or `CLOB`.

[[lob-semantics]]
.*Read more: Semantics of the @Lob annotation*
[%collapsible]
====
****
What the spec actually says is that the field should be persisted

> ...as a large object to a database-supported large object type.

It's quite unclear what this means, and the spec goes on to say that

> ...the treatment of the `Lob` annotation is provider-dependent...

which doesn't help much.
****
====

Hibernate interprets this annotation in what we think is the most reasonable way.
In Hibernate, an attribute annotated `@Lob` is written to JDBC using the `setClob()` or `setBlob()` method of `PreparedStatement`, and is read from JDBC using the `getClob()` or `getBlob()` method of `ResultSet`.

Now, the use of these JDBC methods is usually unnecessary!
JDBC drivers are perfectly capable of converting between `String` and `CLOB` or between `byte[]` and `BLOB`.
So unless you specifically need to use these JDBC LOB APIs, you _don't_ need the `@Lob` annotation.

Instead, as we just saw in <<column-lengths>>, all you need is to specify a large enough column `length` to accommodate the data you plan to write to that column.

You should usually write this:
[source,java]
----
@Column(length=LONG32) // good, correct column type inferred
String text;
----
instead of this:
[source,java]
----
@Lob // almost always unnecessary
String text;
----

This is particularly true for PostgreSQL.

[%unbreakable]
.*Read more: PostgreSQL and @Lob*
[%collapsible]
// .PostgreSQL `BYTEA` and `TEXT`
====
****
Unfortunately, the driver for PostgreSQL doesn't allow `BYTEA` or `TEXT` columns to be read via the JDBC LOB APIs.

This limitation of the Postgres driver has resulted in a whole cottage industry of bloggers and stackoverflow question-answerers recommending convoluted ways to hack the Hibernate `Dialect` for Postgres to allow an attribute annotated `@Lob` to be written using `setString()` and read using `getString()`.

But simply removing the `@Lob` annotation has exactly the same effect.

Conclusion:

- on PostgreSQL, `@Lob` always means the `OID` type,
- `@Lob` should never be used to map columns of type `BYTEA` or `TEXT`, and
- please don't believe everything you read on stackoverflow.
****
====

Finally, as an alternative, Hibernate lets you declare an attribute of type `java.sql.Blob` or `java.sql.Clob`.

[source,java]
----
@Entity
class Book {
    ...
    Clob text;
    Blob coverArt;
    ....
}
----

The advantage is that a `java.sql.Clob` or `java.sql.Blob` can in principle index up to 2^63^ characters or bytes, much more data than you can fit in a Java `String` or `byte[]` array (or in your computer).

To assign a value to these fields, we'll need to use a link:{doc-javadoc-url}org/hibernate/LobHelper.html[`LobHelper`].
We can get one from the `Session`:

[source,java]
----
LobHelper helper = session.getLobHelper();
book.text = helper.createClob(text);
book.coverArt = helper.createBlob(image);
----

In principle, the `Blob` and `Clob` objects provide efficient ways to read or stream LOB data from the server.

[source,java]
----
Book book = session.find(Book.class, bookId);
String text = book.text.getSubString(1, textLength);
InputStream bytes = book.coverArt.getBinaryStream();
----

Of course, the behavior here depends very much on the JDBC driver, and so we really can't promise that this is a sensible thing to do on your database.

[[mapping-embeddables]]
=== Mapping embeddable types to UDTs or to JSON

There's a couple of alternative ways to represent an embeddable type on the database side.

[[embeddable-udt]]
[discrete]
==== Embeddables as UDTs

First, a really nice option, at least in the case of Java record types, and for databases which support _user-defined types_ (UDTs), is to define a UDT which represents the record type.
This is easy: just annotate the record type, or the attribute which holds a reference to it, with the new `@Struct` annotation:

[source,java]
----
@Embeddable
@Struct(name="PersonName")
record Name(String firstName, String middleName, String lastName) {}
----
[source,java]
----
@Entity
class Person {
    ...
    Name name;
    ...
}
----

This results in the following UDT:

[source,sql]
----
create type PersonName as (firstName varchar(255), middleName varchar(255), lastName varchar(255))
----

And the `name` column of the `Author` table will have the type `PersonName`.

[discrete]
==== Embeddables to JSON

A second option that's available is to map the embeddable type to a `JSON` (or `JSONB`) column.
Now, this isn't something we would exactly _recommend_ if you're defining a data model from scratch, but it's at least useful for mapping pre-existing tables with JSON-typed columns.
Since embeddable types are nestable, we can map some JSON formats this way, and even query JSON properties using HQL.

To map an attribute of embeddable type to JSON, we must annotate the attribute `@JdbcTypeCode(SqlTypes.JSON)`, instead of annotating the embeddable type.
But the embeddable type `Name` should still be annotated `@Embeddable` if we want to query its attributes using HQL.

[source,java]
----
@Embeddable
record Name(String firstName, String middleName, String lastName) {}
----
[source,java]
----
@Entity
class Person {
    ...
    @JdbcTypeCode(SqlTypes.JSON)
    Name name;
    ...
}
----

We also need to add Jackson or an implementation of JSONB--for example, Yasson--to our runtime classpath.
To use Jackson we could add this line to our Gradle build:

[source,groovy,subs="attributes+"]
----
runtimeOnly 'tools.jackson.core:jackson-databind:{jackson3Version}'
----

Now the `name` column of the `Author` table will have the type `jsonb`, and Hibernate will automatically use Jackson to serialize a `Name` to and from JSON format.

[[miscellaneous-mappings]]
=== Summary of SQL column type mappings

So, as we've seen, there are quite a few annotations that affect the mapping of Java types to SQL column types in DDL.
Here we summarize the ones we've just seen in the second half of this chapter, along with some we already mentioned in earlier chapters.

.Annotations for mapping SQL column types
[%autowidth.stretch]
|===
| Annotation | Interpretation

| `@Enumerated`, `@EnumeratedValue` | Specify how an <<enums,`enum` type should be persisted>>
| `@Nationalized` | Use a <<nationalized-chars,nationalized character type>>: `NCHAR`, `NVARCHAR`, or `NCLOB`
| `@Lob` 💀 | Use <<lobs,JDBC LOB APIs>> to read and write the annotated attribute
| `@Array` | Map a collection to a <<arrays,SQL `ARRAY` type>> of the specified length
| `@Struct` | Map an <<embeddable-udt,embeddable to a SQL UDT>> with the given name
| `@TimeZoneStorage` | Specify how the link:{doc-javadoc-url}org/hibernate/annotations/TimeZoneStorageType.html[time zone information should be persisted]
| `@JdbcType` or `@JdbcTypeCode` | Use an implementation of <<jdbc-type,`JdbcType`>> to map an arbitrary SQL type
| `@Collate` | Specify a collation for a column
|===

In addition, there are link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html[some configuration properties] which have a _global_ effect on how basic types map to SQL column types:

.Type mapping settings
[%autowidth.stretch]
|===
| Configuration property name | Purpose

| `hibernate.use_nationalized_character_data` | Enable use of <<nationalized-chars,nationalized character types>> by default
| `hibernate.type.preferred_boolean_jdbc_type` | Specify the default SQL column type for storing a `boolean`
| `hibernate.type.preferred_uuid_jdbc_type` | Specify the default SQL column type for storing a `UUID`
| `hibernate.type.preferred_duration_jdbc_type` | Specify the default SQL column type for storing a `Duration`
| `hibernate.type.preferred_instant_jdbc_type` | Specify the default SQL column type for storing an `Instant`
| `hibernate.timezone.default_storage` | Specify the default strategy for link:{doc-javadoc-url}org/hibernate/annotations/TimeZoneStorageType.html[storing time zone information]
| `hibernate.type.prefer_native_enum_types` | Use <<named-enums,named enum types>> on PostgreSQL and Oracle
|===

Earlier, we saw how to use these settings to control the default mappings for <<datetime-types,`Instant` and `Duration`>>.

[TIP]
====
These are _global_ settings and thus quite clumsy.
We recommend against messing with any of these settings unless you have a really good reason for it.
====

There's one more topic we would like to cover in this chapter.

[[mapping-formulas]]
=== Mapping to formulas

Hibernate lets us map an attribute of an entity to a SQL formula involving columns of the mapped table.
Thus, the attribute is a sort of "derived" value.

.Annotations for mapping formulas
[%autowidth.stretch]
|===
| Annotation | Purpose

| link:{doc-javadoc-url}org/hibernate/annotations/Formula.html[`@Formula`] | Map an attribute to a SQL formula
| `@JoinFormula` | Map an association to a SQL formula
| `@DiscriminatorFormula` | Use a SQL formula as the discriminator in <<mapping-inheritance,single table inheritance>>.
|===

For example:

[source,java]
----
@Entity
class Order {
    ...
    @Column(name = "sub_total", scale=2, precision=8)
    BigDecimal subTotal;

    @Column(name = "tax", scale=4, precision=4)
    BigDecimal taxRate;

    @Formula("sub_total * (1.0 + tax)")
    BigDecimal totalWithTax;
    ...
}
----

The formula is evaluated every time the entity is read from the database.

[[derived-identity]]
=== Derived Identity

An entity has a _derived identity_ if it inherits part of its primary key from an associated "parent" entity.
We've already met a kind of degenerate case of _derived identity_ when we talked about <<one-to-one-pk,one-to-one associations with a shared primary key>>.

But a `@ManyToOne` association may also form part of a derived identity.
That is to say, there could be a foreign key column or columns included as part of the composite primary key.
There's three different ways to represent this situation on the Java side of things:

- using `@IdClass` without `@MapsId`,
- using `@IdClass` with `@MapsId`, or
- using `@EmbeddedId` with `@MapsId`.

Let's suppose we have a `Parent` entity class defined as follows:

[source,java]
----
@Entity
class Parent {
    @Id
    Long parentId;

    ...
}
----

The `parentId` field holds the primary key of the `Parent` table, which will also form part of the composite primary key of every `Child` belonging to the `Parent`.

[discrete]
==== First way

In the first, slightly simpler approach, we define an `@IdClass` to represent the primary key of `Child`:

[source,java]
----
class DerivedId {
    Long parent;
    String childId;

    // constructors, equals, hashcode, etc
    ...
}
----

And a `Child` entity class with a `@ManyToOne` association annotated `@Id`:

[source,java]
----
@Entity
@IdClass(DerivedId.class)
class Child {
    @Id
    String childId;

    @Id @ManyToOne
    @JoinColumn(name="parentId")
    Parent parent;

    ...
}
----

Then the primary key of the `Child` table comprises the columns `(childId,parentId)`.

[discrete]
==== Second way

This is fine, but sometimes it's nice to have a field for each element of the primary key.
We may use the `@MapsId` annotation we met <<one-to-one-pk,earlier>>:

[source,java]
----
@Entity
@IdClass(DerivedId.class)
class Child {
    @Id
    Long parentId;
    @Id
    String childId;

    @ManyToOne
    @MapsId(Child_.PARENT_ID) // typesafe reference to Child.parentId
    @JoinColumn(name="parentId")
    Parent parent;

    ...
}
----

We're using the approach we saw <<mapped-by-metamodel,previously>> to refer to the `parentId` property of `Child` in a typesafe way.

Note that we must place column mapping information on the association annotated `@MapsId`, not on the `@Id` field.

We must slightly modify our `@IdClass` so that field names align:

[source,java]
----
class DerivedId {
    Long parentId;
    String childId;

    // constructors, equals, hashcode, etc
    ...
}
----

[discrete]
==== Third way

The third alternative is to redefine our `@IdClass` as an `@Embeddable`.
We don't actually need to change the `DerivedId` class, but we do need to add the annotation.

[source,java]
----
@Embeddable
class DerivedId {
    Long parentId;
    String childId;

    // constructors, equals, hashcode, etc
    ...
}
----

Then we may use `@EmbeddedId` in `Child`:

[source,java]
----
@Entity
class Child {
    @EmbeddedId
    DerivedId id;

    @ManyToOne
    @MapsId(DerivedId_.PARENT_ID) // typesafe reference to DerivedId.parentId
    @JoinColumn(name="parentId")
    Parent parent;

    ...
}
----

The <<composite-identifiers,choice>> between `@IdClass` and `@EmbeddedId` boils down to taste.
The `@EmbeddedId` is perhaps a little DRYer.

[[constraints]]
=== Adding constraints

Database constraints are important.
Even if you're sure that your program has no bugs 🧐, it's probably not the only program with access to the database.
Constraints help ensure that different programs (and human administrators) play nicely with each other.

Hibernate adds certain constraints to generated DDL automatically: primary key constraints, foreign key constraints, and some unique constraints.
But it's common to need to:

- add additional unique constraints,
- add check constraints, or
- customize the name of a foreign key constraint.

We've <<join-column-mappings,already seen>> how to use `@ForeignKey` to specify the name of a foreign key constraint.

There are two ways to add a unique constraint to a table:

- using `@Column(unique=true)` to indicate a single-column unique key, or
- using the `@UniqueConstraint` annotation to define a uniqueness constraint on a combination of columns.

[source,java]
----
@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames={"title", "year", "publisher_id"}))
class Book { ... }
----

This annotation looks a bit ugly perhaps, but it's actually useful even as documentation.

The `@CheckConstraint` annotation adds a check constraint to the table.

[source,java]
----
@Entity
@Table(check = @CheckConstraint(name="ValidISBN", constraint="length(isbn)=13"))
class Book { ... }
----

This annotation is commonly used at the field level:

[source,java]
----
@Id
@Column(check = @CheckConstraint(constraint="length(isbn)=13"))
String isbn;
----

---

### Documentation Src Main Asciidoc Introduction Preface (`documentation/src/main/asciidoc/introduction/Preface.adoc`)

[[preface]]
== Preface

:persistence: https://jakarta.ee/specifications/persistence/4.0/jakarta-persistence-spec-4.0-M4.pdf
:data: https://jakarta.ee/specifications/data/1.1/jakarta-data-1.1-m3.pdf
:query: https://jakarta.ee/specifications/query/1.0/jakarta-query-1.0-m2.pdf

Hibernate 8 is the culmination of six years of sustained effort focused on modernizing the most popular persistence solution for Java.
Ushering in the new generation of Jakarta specifications--Persistence 4.0, Query 1.0, and Data 1.1--it represents a new state of the art in persistence and object relational mapping.
No other persistence solution in any programming language comes even close to offering a comparable breadth of features, ease of use, or level of compile time type safety.

.*Read more: A brief recap*
[%collapsible]
====
****
- Hibernate 6 was a major redesign of the world's most popular and feature-rich ORM solution.
The redesign touched almost every subsystem of Hibernate, including the APIs, mapping annotations, and the query language.
This new Hibernate was suddenly more powerful, more robust, more portable, and more type safe.

- Hibernate 7 built on this foundation, adding support for link:{persistence}[JPA 3.2], and introducing https://hibernate.org/repositories/[Hibernate Data Repositories], an implementation of the link:{data}[Jakarta Data specification].
Taken together, these enhancements yielded a level of compile-time type safety--and resulting developer productivity--which was previously impossible.
 In its last dying breath, Hibernate 7.4 added an integrated and extensible system for dealing with temporal data and audit logging.

- In the background, plans for JPA 4 were being laid and executed.
  Jakarta Persistence 4.0 finally makes it possible to access almost the full power of Hibernate via the standard API interfaces and improves the programming model considerably.
  Jakarta Data 1.1 is now fully integrated with Jakarta Persistence and features powerful enhancements that make it easier than ever to deal with dynamic queries.
  Jakarta Query 1.0 finally provides a rigorous definition of the query language.
****
====

// Hibernate ORM and https://hibernate.org/reactive/[Hibernate Reactive] are core components of https://quarkus.io[Quarkus 3], the most exciting new environment for cloud-native development in Java, and Hibernate remains the persistence solution of choice for almost every major Java framework or server.

Recent rapid evolution has obsoleted much of the information about Hibernate that's available in books, in blog posts, and on stackoverflow.
Indeed, the changes in JPA 4 required significant rewriting of even this document.

This guide is an up-to-date, high-level discussion of the current feature set and recommended usage.
It does not attempt to cover every feature and should be used in conjunction with other documentation:

- Hibernate's extensive link:{doc-javadoc-url}[Javadoc],
- the link:{doc-query-language-url}[Guide to Hibernate Query Language],
- link:{doc-data-repositories-url}[Introducing Hibernate Data Repositories], and
- the Hibernate link:{doc-user-guide-url}[User Guide].

[NOTE]
====
The Hibernate User Guide includes detailed discussions of most aspects of Hibernate.
But with so much information to cover, readability is difficult to achieve, and so it's most useful as a reference.
Where necessary, we'll provide links to relevant sections of the User Guide.
====

---

### Documentation Src Main Asciidoc Introduction Processor (`documentation/src/main/asciidoc/introduction/Processor.adoc`)

[[generator]]
== Compile-time tooling

:generator: https://hibernate.org/orm/processor/
:generator-guide: {doc-user-guide-url}#tooling-modelgen

The _static metamodel generator_ is a standard part of JPA.
// It's an annotation processor that produces a statically-typed metamodel of the entity classes in a Java program.
We've actually already seen its handiwork in the code examples <<main-hibernate,earlier>>: it's the author of the class `Book_`, which contains the static metamodel of the <<book,entity class>> `Book`.

Hibernate comes with an {generator}[annotation processor] which does much more than just this.
It's capable of automatically generating:

- <<static-metamodel,JPA metamodel>> classes, as we've already seen,
- link:{doc-data-repositories-url}#data-static-metamodel[Jakarta Data metamodel] classes,
- static <<generated-query-methods,query methods>> and <<generated-finder-methods,finder methods>>, and
- implementations of <<static-or-instance,repository interfaces>>, including link:{doc-data-repositories-url}#repository-interfaces[Jakarta Data repositories].

[[metamodel-generator]]
.*Read more: The changing role of Hibernate Processor*
[%collapsible]
====
****

{generator}[Hibernate Processor], the annotation processor formerly known as the Metamodel Generator, began its life as a code generator for what JPA calls a https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2#a6072[_static metamodel_].
That is, it produces a typed model of the persistent classes in our program, giving us a type safe way to refer to their attributes in Java code.
In particular, it lets us specify <<entity-graph,entity graphs>> and <<criteria-queries,criteria queries>> in a completely type-safe way.

The history behind this thing is quite interesting.
Back when Java's annotation processing API was brand spankin' new, the static metamodel for JPA was proposed by Gavin King for inclusion in JPA 2.0, as a way to achieve type safety in the nascent criteria query API.
It's fair to say that, back in 2010, this API was not a runaway success.
Tools did not, at the time, feature robust support for annotation processors.
And all the explicit generic types made user code quite verbose and difficult to read.
(The need for an explicit reference to a `CriteriaBuilder` instance also contributed verbosity to the criteria API.)
For years, Gavin counted this as one of his more embarrassing missteps.

But time has been kind to the static metamodel.
By now, all Java compilers, build tools, and IDEs have robust support for annotation processing, and Java's local type inference (the `var` keyword) eliminates the verbose generic types.
JPA's `CriteriaBuilder` and `EntityGraph` APIs are still not quite perfect, but the imperfections aren't related to static type safety or annotation processing.
The static metamodel itself is undeniably useful and elegant.

And it turns out that there was quite a lot of unlocked potential there.
Since Hibernate 6.3 the Processor has started taking on a much bigger role.
Today, it even contains a link:{doc-data-repositories-url}[complete implementation of the Jakarta Data specification].

Now, you still don't have to use the Hibernate Processor with Hibernate—the APIs we just mentioned still also accept plain strings—but we find that it works well with Gradle and integrates smoothly with our IDE, and the advantage in type-safety is compelling.
****
====

[TIP]
====
We've already seen how to set up the annotation processor in the <<hello-hibernate,Gradle build>> we saw earlier.
For more details on how to integrate the Hibernate Processor, check out the {generator-guide}[Static Metamodel Generator] section in the User Guide.
====

[[static-metamodel]]
=== The static metamodel

We've already seen several ways to use the JPA static metamodel.
Metamodel references are useful for expressing, in a completely type-safe way:

- <<criteria-queries,Criteria queries>>,
- eager fetching via an <<entity-graph,entity graph>>,
- dynamic <<restrictions-and-ordering,restriction and sorting>>, and
- references to named <<named-queries,queries>> and named entity graphs.

Here's an example of the sort of code that's generated for an entity class, as mandated by the JPA specification:

[source,java]
.Generated Code
----
/**
 * Static metamodel for {@link org.example.Book}
 **/
@StaticMetamodel(Book.class)
public abstract class Book_ {

	/**
	 * Static metamodel type for {@link org.example.Book}
	 **/
	public static volatile EntityType<Book> class_;

	/**
	 * Static metamodel for attribute {@link org.example.Book#isbn}
	 **/
    public static volatile TextAttribute<Book> isbn;

    /**
     * Static metamodel for attribute {@link org.example.Book#text}
     **/
    public static volatile TextAttribute<Book> text;

    /**
     * Static metamodel for attribute {@link org.example.Book#title}
     **/
    public static volatile TextAttribute<Book> title;

    /**
     * Static metamodel for attribute {@link org.example.Book#type}
     **/
    public static volatile ComparableAttribute<Book, Type> type;

    /**
     * Static metamodel for attribute {@link org.example.Book#publicationDate}
     **/
    public static volatile TemporalAttribute<Book, LocalDate> publicationDate;

    /**
     * Static metamodel for attribute {@link org.example.Book#publisher}
     **/
    public static volatile SingularAttribute<Book, Publisher> publisher;

    /**
     * Static metamodel for attribute {@link org.example.Book#authors}
     **/
    public static volatile SetAttribute<Book, Author> authors;

    public static final String ISBN = "isbn";
    public static final String TEXT = "text";
    public static final String TITLE = "title";
    public static final String TYPE = "type";
    public static final String PUBLICATION_DATE = "publicationDate";
    public static final String PUBLISHER = "publisher";
    public static final String AUTHORS = "authors";

}
----

For each attribute of the entity, the `Book_` class has:

1. a `String`-valued constant like `TITLE` , and
2. a typesafe reference like `title` to a metamodel object of type `Attribute`.

[TIP]
====
Hibernate Processor allows _statically-typed_ access to elements of the JPA `Metamodel`. But the `Metamodel` is also accessible in a "reflective" way, via the `EntityManagerFactory`.

[source,java]
----
EntityType<Book> book = entityManagerFactory.getMetamodel().entity(Book.class);
SingularAttribute<Book,Long> id = book.getDeclaredId(Long.class)
----
// SingularAttribute<Book,String> title = book.getDeclaredSingularAttribute("title", String.class)

This is very useful for writing generic code in frameworks or libraries.
For example, you could use it to create your own criteria query API.
====

The JPA static metamodel for an entity also contains members representing the named queries and named entity graphs declared by `@NamedQuery`, `@NamedNativeQuery`, and `@NamedEntityGraph` annotations of the entity class.

For example, if we had:

[source,java]
----
@CheckHQL // validate named queries at compile time
@NamedQuery(name = "findBooksByTitle",
            query = "from Book where title like :title order by title")
@Entity
class Book { ... }
----

Then we may execute the query as follows:

[source,java]
----
var books =
        entityManager.createNamedQuery(Queries_._findBooksByTitle_)
                .setParameter("title", titlePattern)
                .setPage(page)
                .getResultList();
----

Notice that no typecast was required here, since the generated code embeds the return type of the query as a type argument of the JPA `TypedQueryReference`:

[source,java]
----
/**
 * @see #_findBooksByTitle_
 **/
public static final String QUERY_FIND_BOOKS_BY_TITLE = "findBooksByTitle";


/**
 * The query named {@value QUERY_FIND_BOOKS_BY_TITLE}
 * <pre>
 * from Book where title like :title order by title
 * </pre>
 *
 * @see org.example.Book
 **/
public static volatile TypedQueryReference<Book> _findBooksByTitle_;
----

[TIP]
====
Actually, Hibernate Processor doesn't require that such annotations be applied to the entity class itself.
====

We've already been using metamodel references like `Book_.authors` and `Book.AUTHORS` in the previous chapters.
So now let's see what else Hibernate Processor can do for us.

[[finders-queries-repositories]]
=== Finder methods, query methods, and repositories

Automatic generation of _finder methods_ and _query methods_ is a relatively new feature of Hibernate Processor--originally introduced as an experiment--which ultimately grew into a whole new way to use Hibernate and, eventually, a whole new Jakarta specification.

[IMPORTANT]
====
The rest of this chapter is optional.
If you're happy with the approach taken by Jakarta Data, you're welcome to skip it completely, and move on to <<tuning-and-performance>>.

The functionality we’re about to describe was developed before Jakarta Data took on its current shape, and directly triggered the apocalypse which lead to the final form of the specification. Therefore, there’s massive overlap between the functionality described in this chapter, and the functionality available via the Jakarta Data annotations.

For information about the Jakarta Data-centric version of this functionality, please refer to link:{doc-data-repositories-url}[Introducing Hibernate Data Repositories].
====

We're going to meet three different kinds of generated method:

- a _<<generated-named-queries,named query method>>_ has its signature and implementation generated directly from a `@NamedQuery` annotation,
- a _<<generated-query-methods,query method>>_ has a signature that's explicitly declared, and a generated implementation which executes a HQL or SQL query specified via a `@HQL` or `@SQL` annotation, and
- a _<<generated-finder-methods,finder method>>_ annotated `@Find` has a signature that's explicitly declared, and a generated implementation inferred from the parameter list.

We're also going to see two ways that these methods can be called:

- as static methods of a generated abstract class, or
- as <<static-or-instance,instance methods of an interface>> with a generated implementation which may even be <<cdi-bean-injection,injected>>.

Back in <<organizing-persistence>>, we showed you how to organize persistence logic using a Jakarta Data repository.
Repositories are a sweet spot for many users, but they might not be your sweet spot, and that's OK.
Hibernate Processor is perfectly happy to generate `static` implementations of `@HQL`, `@SQL`, and `@Find` methods, eliminating the need to inject or instantiate a repository object.

// [IMPORTANT]
// ====
// // For many years we've followed a three-step process: implement, learn from experience, and then standardize.
// //
// The functionality we're about to describe was developed before Jakarta Data took on its current shape, and directly triggered the apocalypse which lead to the final form of the specification.
// Therefore, there's massive overlap between the functionality described in this chapter, and the functionality available via the Jakarta Data annotations.
// On the other hand, Jakarta Data can't do _everything_ described below.
//
// We've therefore opted _not_ to rewrite this chapter in a Jakarta Data-centric way, and instead refer you to link:{doc-data-repositories-url}[Introducing Hibernate Data Repositories] for information about the standard Jakarta Data APIs.
// ====

[CAUTION]
====
The functionality described in the rest of this chapter depends on the use of the annotations described in <<entities>>.
Hibernate Processor is not currently able to generate finder methods and query methods for entities declared completely in XML, and it's not able to validate HQL which queries such entities.
(On the other hand, the <<object-relational-mapping,O/R mappings>> may be specified in XML, since they're not needed by the Processor.)
====

To whet our appetites, let's see how it works for a `@NamedQuery`.

[[generated-named-queries]]
=== Named queries and Hibernate Processor

The very simplest way to generate a query method is to put a `@NamedQuery` annotation anywhere we like, with a `name` beginning with the magical character `#`.

Let's just stick it on the `Book` class:

[source,java]
----
@CheckHQL // validate the query at compile time
@NamedQuery(name = "#findByTitleAndType",
            query = "select book from Book book where book.title like :title and book.type = :type")
@Entity
public class Book { ... }
----

Now the Processor adds the following method declaration to the metamodel class `Book_`.

[source,java]
.Generated Code
----
/**
 * Execute named query {@value #QUERY_FIND_BY_TITLE_AND_TYPE} defined by annotation of {@link Book}.
 **/
public static List<Book> findByTitleAndType(@Nonnull EntityManager entityManager, String title, Type type) {
    return entityManager.createNamedQuery(QUERY_FIND_BY_TITLE_AND_TYPE)
            .setParameter("title", title)
            .setParameter("type", type)
            .getResultList();
}
----

We can easily call this method from wherever we like, as long as we have access to an `EntityManager`:

[source,java]
----
List<Book> books =
        Book_.findByTitleAndType(entityManager, titlePattern, Type.BOOK);
----

Now, this is quite nice, but it's a bit inflexible in various ways, and so this probably _isn't_ the best way to generate a query method.

[[generated-query-methods]]
=== Generated query methods

The principal problem with generating the query method straight from the `@NamedQuery` annotation is that it doesn't let us explicitly specify the return type or parameter list.
In the case we just saw, Hibernate Processor does a reasonable job of inferring the query return type and parameter types, but we're often going to need a bit more control.

The solution is to write down the signature of the query method _explicitly_, as an abstract method in Java.
We'll need a place to put this method, and since our `Book` entity isn't an abstract class, we'll just introduce a new interface for this purpose:

[source,java]
----
interface Queries {
    @HQL("where title like :title and type = :type")
    List<Book> findBooksByTitleAndType(String title, String type);
}
----

Instead of `@NamedQuery`, which is a type-level annotation, we specify the HQL query using the new `@HQL` annotation, which we place directly on the query method.
This results in the following generated code in the `Queries_` class:

[source,java]
.Generated Code
----
@StaticMetamodel(Queries.class)
public abstract class Queries_ {

    /**
     * Execute the query {@value #FIND_BOOKS_BY_TITLE_AND_TYPE_String_Type}.
     *
     * @see org.example.Queries#findBooksByTitleAndType(String,Type)
     **/
    public static List<Book> findBooksByTitleAndType(@Nonnull EntityManager entityManager, String title, Type type) {
		return entityManager.createQuery(FIND_BOOKS_BY_TITLE_AND_TYPE_String_Type, Book.class)
                .setParameter("title", title)
                .setParameter("type", type)
                .getResultList();
    }

    static final String FIND_BOOKS_BY_TITLE_AND_TYPE_String_Type =
            "where title like :title and type = :type";

}

----

Notice that the signature differs just slightly from the one we wrote down in the `Queries` interface: the Processor has prepended a parameter accepting `EntityManager` to the parameter list.

If we want to explicitly specify the name and type of this parameter, we may declare it explicitly:

[source,java]
----
interface Queries {
    @HQL("where title like :title and type = :type")
    List<Book> findBooksByTitleAndType(EntityAgent agent, String title, String type);
}
----

Hibernate Processor defaults to using `EntityManager` as the session type, but other types are allowed:

- `EntityAgent`,
- `Session` or `StatelessSession`, or
- `Mutiny.Session` or `Mutiny.StatelessSession` from Hibernate Reactive.

The real value of all this is in the checks which can now be done at compile time.
Hibernate Processor verifies that the parameters of our abstract method declaration match the parameters of the HQL query, for example:

- for a named parameter `:alice`, there must be a method parameter named `alice` with exactly the same type, or
- for an ordinal parameter `?2`, the second method parameter must have exactly the same type.

The query must also be syntactically legal and semantically well-typed, that is, the entities, attributes, and functions referenced in the query must actually exist and have compatible types.
Hibernate Processor determines this by inspecting the annotations of the entity classes at compile time.

[NOTE]
====
The `@CheckHQL` annotation which instructs Hibernate to validate named queries is _not_ necessary for query methods annotated `@HQL`.
====

The `@HQL` annotation has a friend named `@SQL` which lets us specify a query written in native SQL instead of in HQL.
In this case there's a lot less the Processor can do to check that the query is legal and well-typed.

We imagine you're wondering whether a `static` method is really the right thing to use here.

[[static-or-instance]]
=== Generating query methods as instance methods

One thing not to like about what we've just seen is that we can't transparently replace a generated `static` function of the `Queries_` class with an improved handwritten implementation without impacting clients.
Now, if our query is only called in one place, which is quite common, this isn't going to be a big issue, and so we're inclined to think the `static` function is fine.

But if this function is called from many places, it's probably better to promote it to an instance method of some class or interface.
Fortunately, this is straightforward.

All we need to do is add an abstract getter method for the session object to our `Queries` interface.
(And remove the session from the method parameter list.)
We may call this method anything we like:

[source,java]
----
interface Queries {
    EntityManager entityManager();

    @HQL("where title like :title and type = :type")
    List<Book> findBooksByTitleAndType(String title, String type);
}
----

Here we've used `EntityManager` as the session type, but other types are allowed, as we saw above.

Now Hibernate Processor does something a bit different:

[source,java]
.Generated Code
----
public class _Queries implements Queries {

    private final @Nonnull EntityManager entityManager;

    public _Queries(@Nonnull EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public @Nonnull EntityManager entityManager() {
        return entityManager;
    }

    /**
     * Execute the query {@value #FIND_BOOKS_BY_TITLE_AND_TYPE_String_Type}.
     *
     * @see org.example.Queries#findBooksByTitleAndType(String,Type)
     **/
    @Override
    public List<Book> findBooksByTitleAndType(String title, Type type) {
        return entityManager.createQuery(FIND_BOOKS_BY_TITLE_AND_TYPE_String_Type, Book.class)
                .setParameter("title", title)
                .setParameter("type", type)
                .getResultList();
    }

    static final String FIND_BOOKS_BY_TITLE_AND_TYPE_String_Type =
            "where title like :title and type = :type";

}
----

The generated class `_Queries` now implements the `Queries` interface, and the generated query method implements our abstract method directly.

Of course, the protocol for calling the query method has to change:

[source,java]
----
Queries queries = new _Queries(entityManager);
List<Book> books = queries.findByTitleAndType(titlePattern, Type.BOOK);
----

If we ever need to swap out the generated query method with one we write by hand, without impacting clients, all we need to do is replace the abstract method with a `default` method of the `Queries` interface.
For example:

[source,java]
----
interface Queries {
    EntityManager entityManager();

    // handwritten method replacing previous generated implementation
    default List<Book> findBooksByTitleAndType(String title, String type) {
        entityManager()
                .createQuery("where title like :title and type = :type", Book.class)
                        .setParameter("title", title)
                        .setParameter("type", type)
                        .setFlushMode(COMMIT)
                        .setMaxResults(100)
                        .getResultList();
    }
}
----

What if we would like to inject a `Queries` object instead of calling its constructor directly?

[[cdi-bean-injection]]
[%unbreakable]
[TIP]
====
As you <<organizing-persistence,recall>>, we don't think these things really need to be container-managed objects.
But if you _want_ them to be--if you're allergic to calling constructors, for some reason--then:

- placing `jakarta.inject` on the build path will cause an `@Inject` annotation to be added to the constructor of `_Queries`, and
- placing `jakarta.enterprise.context` on the build path will cause a `@Dependent` annotation to be added to the `Queries_` class.

Thus, the generated implementation of `Queries` will be a perfectly functional CDI bean with no extra work to be done.
====

Is the `Queries` interface starting to look a lot like a DAO-style repository object?
Well, perhaps.
You can certainly _decide to use_ this facility to create a `BookRepository` if that's what you prefer.
But unlike a repository, our `Queries` interface:

- doesn't attempt to hide the `EntityManager` from its clients,
- doesn't implement or extend any framework-provided interface or abstract class, at least not unless you want to create such a framework yourself, and
- isn't restricted to service a particular entity class.

We can have as many or as few interfaces with query methods as we like.
There's no one-one-correspondence between these interfaces and entity types.
This approach is so flexible that we don't even really know what to call these "interfaces with query methods".

[[generated-finder-methods]]
=== Generated finder methods

At this point, one usually begins to question whether it's even necessary to write a query at all.
Would it be possible to just infer the query from the method signature?

In some simple cases it's indeed possible, and this is the purpose of _finder methods_.
A finder method is a method annotated `@Find`.
For example:

[source,java]
----
@Find
Book getBook(String isbn);
----

A finder method may have multiple parameters:

[source,java]
----
@Find
List<Book> getBooksByTitle(String title, Type type);
----

The name of the finder method is arbitrary and carries no semantics.
But:

- the return type determines the entity class to be queried, and
- the parameters of the method must match the fields of the entity class _exactly_, by both name and type.

Considering our first example, `Book` has a persistent field `String isbn`, so this finder method is legal.
If there were no field named `isbn` in `Book`, or if it had a different type, this method declaration would be rejected with a meaningful error at compile time.
Similarly, the second example is legal, since `Book` has fields `String title` and `Type type`.

[%unbreakable]
[IMPORTANT]
====
You might notice that our solution to this problem is very different from the approach taken by others.
In DAO-style repository frameworks, you're asked to encode the semantics of the finder method into the _name of the method_.
This idea came to Java from Ruby, and we think it doesn't belong here.
It's completely unnatural in Java, and by almost any measure other than _counting characters_ it's objectively worse than just writing the query in a string literal.
At least string literals accommodate whitespace and punctuation characters.
Oh and, you know, it's pretty useful to be able to rename a finder method _without changing its semantics_. 🙄
====

The code generated for this finder method depends on what kind of fields match the method parameters:

[cols="45,~"]
|===
|`@Id` field | Uses `EntityManager.find()`
|All `@NaturalId` fields | Uses `Session.byNaturalId()`
|Other persistent fields, or a mix of field types | Uses a criteria query
|===

The generated code also depends on what kind of session we have, since the capabilities of stateless sessions, and of reactive sessions, differ slightly from the capabilities of regular stateful sessions.

With `EntityManager` as the session type, we obtain:

[source,java]
----
/**
 * Find {@link Book} by {@link Book#isbn isbn}.
 *
 * @see org.example.Dao#getBook(String)
 **/
@Override
public Book getBook(@Nonnull String isbn) {
	return entityManager.find(Book.class, isbn);
}

/**
 * Find {@link Book} by {@link Book#title title} and {@link Book#type type}.
 *
 * @see org.example.Dao#getBooksByTitle(String,Type)
 **/
@Override
public List<Book> getBooksByTitle(String title, Type type) {
	var builder = entityManager.getEntityManagerFactory().getCriteriaBuilder();
	var query = builder.createQuery(Book.class);
	var entity = query.from(Book.class);
	query.where(
			title==null
				? entity.get(Book_.title).isNull()
				: builder.equal(entity.get(Book_.title), title),
			type==null
				? entity.get(Book_.type).isNull()
				: builder.equal(entity.get(Book_.type), type)
	);
	return entityManager.createQuery(query).getResultList();
}
----

It's even possible to match a parameter of a finder method against a property of an associated entity or embeddable.
The natural syntax would be a parameter declaration like `String publisher.name`, but because that's not legal Java, we can write it as `String publisher$name`, taking advantage of a legal Java identifier character that nobody ever uses for anything else:

[source,java]
----
@Find
List<Book> getBooksByPublisherName(String publisher$name);
----

The `@Pattern` annotation may be applied to a parameter of type `String`, indicating that the argument is a wildcarded pattern which will be compared using `like`.

[source,java]
----
@Find
List<Book> getBooksByTitle(@Pattern String title, Type type);
----

Even better, a parameter may be of type `Range<T>`, where `P` is the type of the matching field.

[source,java]
----
@Find
List<Book> getBooksByTitle(Range<String> title, Type type);
----

The link:{doc-javadoc-url}org/hibernate/query/range/Range.html[`Range`] interface has a variety of `static` methods the caller may use to construct different kinds of ranges.
For example, `Range.pattern()` constructs a `Range` representing a pattern.

[source,java]
----
List<Book> books =
        // returns books with titles beginning with "hibernate"
        queries.getBooksByTitle(Range.prefix("hibernate", false), type);
----

A finder method may specify <<fetch-profiles,fetch profiles>>, for example:

[source,java]
----
@Find(namedFetchProfiles=Book_.FETCH_WITH_AUTHORS)
Book getBookWithAuthors(String isbn);
----

This lets us declare which associations of `Book` should be pre-fetched by annotating the `Book` class.


// In an interface or abstract class, write down the "signature" of the query as a function, and specify the HQL or SQL query string itself using a `@HQL` or `@SQL` annotation:
//
// [source,java]
// ----
// interface Queries {
//     @HQL("from Book where title like :title order by title offset :start fetch first :max rows only")
//     List<Book> findBooksTitled(String title, int max, int start);
// }
// ----
//
//
// A query method with a similar signature and return type is generated in the corresponding static metamodel class `Queries_`.
// We can call the generated query method like this:
//
// [source,java]
// ----
// List<Book> books =
//         Queries_.findBooksTitled(entityManager, titlePattern,
//                         RESULTS_PER_PAGE, page*RESULTS_PER_PAGE);
// ----

[[paging-and-ordering]]
=== Paging, ordering, and restrictions

Optionally, a query method--or a finder method which returns multiple results--may have additional "magic" parameters which do not map to query parameters:

[cols="19,~,32m"]
|===
| Parameter type | Purpose | Example argument

| `Page` | Specifies a page of query results | Page.first(20)
| `Order<? super E>` | Specifies an entity attribute to order by, if `R` is the entity type returned by the query | Order.asc(Book_.title)
| `List<Order? super E>` +
(or varargs) | Specifies entity attributes to order by, if `R` is the entity type returned by the query | List.of(Order.asc(Book_.title), Order.asc(Book_.isbn))
| `Order<Object[]>` | Specifies a column to order by, if the query returns a projection list | Order.asc(1)
| `List<Object[]>` +
(or varargs) | Specifies columns to order by, if the query returns a projection list | List.of(Order.asc(1), Order.desc(2))
| `Restriction<? super E>` | Specifies a restriction used to filter query results | Restriction.startsWith("Hibernate")
|===

Thus, if we redefine our earlier query method as follows:

[source,java]
----
interface Queries {
    @HQL("from Book where title like :title and type = :type")
    List<Book> findBooksByTitleAndType(String title, Type type,
                                       Page page, Order<? super Book>... order);
}
----

Then we can call it like this:

[source,java]
----
List<Book> books =
        Queries_.findBooksByTitleAndType(entityManager, titlePattern, Type.BOOK,
                Page.page(RESULTS_PER_PAGE, page), Order.asc(Book_.isbn));
----

Alternatively, we could have written this query method as a finder method:

[source,java]
----
interface Queries {
    @Find
    List<Book> getBooksByTitle(String title, Type type,
                               Page page, Order<? super Book>... order);
}
----

Similarly, we may define a query method which accepts an arbitrary ``Restriction``:

[source,java]
----
interface Queries {
    @Find
    List<Book> findBooks(Restriction<? super Book> restriction, Order<? super Book>... order);
}
----

As we <<restrictions-and-ordering,saw earlier>>, the `Restriction` interface has a variety of `static` methods for constructing restrictions.

[source,java]
----
List<Book> books =
        // returns books with titles beginning with "hibernate", sorted by title
        queries.findBooks(Restriction.startsWith(Book_.title, "hibernate", false),
                          Order.asc(Book_.title));
----

This gives some dynamic control over query execution.
We'll see <<return-query-from-method-example,below>> that it's even possible for the caller to gain direct control over the `Query` object.

[[key-based-paging]]
=== Key-based pagination

A generated query or finder method can make use of <<key-based-pagination,key-based pagination>>.

[source,java]
----
@Query("where publicationDate > :minDate")
KeyedResultList<Book> booksFromDate(Session session, LocalDate minDate, KeyedPage<Book> page);
----

Note that this method:

- accepts a `KeyedPage`, and
- returns `KeyedResultList`.

Such a method may be used like this:

[source,java]
----
// obtain the first page of results
KeyedResultList<Book> first =
        Queries_.booksFromDate(session, minDate,
                Page.first(25).keyedBy(Order.asc(Book_.isbn)));
List<Book> firstPage = first.getResultList();
...

if (!firstPage.isLastPage()) {
    // obtain the second page of results
    KeyedResultList<Book> second =
            Queries_.booksFromDate(session, minDate,
                    firstPage.getNextPage());
    List<Book> secondPage = second.getResultList();
    ...
}
----

[[return-types]]
=== Query and finder method return types

A query method doesn't need to return `List`.
It might return a single `Book`.

[source,java]
----
@HQL("where isbn = :isbn")
Book findBookByIsbn(String isbn);
----

For a query with a projection list, `Object[]` or `List<Object[]>` is permitted:

[source,java]
----
@HQL("select isbn, title from Book where isbn = :isbn")
Object[] findBookAttributesByIsbn(String isbn);
----

But when there's just one item in the `select` list, the type of that item should be used:

[source,java]
----
@HQL("select title from Book where isbn = :isbn")
String getBookTitleByIsbn(String isbn);
----

[source,java]
----
@HQL("select local datetime")
LocalDateTime getServerDateTime();
----

A query which returns a selection list may have a query method which repackages the result as a record, as we saw in <<projection-lists>>.

[source,java]
----
record IsbnTitle(String isbn, String title) {}

@HQL("select isbn, title from Book")
List<IsbnTitle> listIsbnAndTitleForEachBook(Page page);
----

A query method might even return `TypedQuery` or `SelectionQuery`:

[[return-query-from-method-example]]
[source,java]
----
@HQL("where title like :title")
SelectionQuery<Book> findBooksByTitle(String title);
----

This is extremely useful at times, since it allows the client to further manipulate the query:

[source,java]
----
List<Book> books =
        Queries_.findBooksByTitle(entityManager, titlePattern)
            .setOrder(Order.asc(Book_.title))                   // order the results
            .setPage(Page.page(RESULTS_PER_PAGE, page))         // return the given page of results
            .setFlushMode(FlushModeType.COMMIT)                 // don't flush session before query execution
            .setReadOnly(true)                                  // load the entities in read-only mode
            .setCacheStoreMode(CacheStoreMode.BYPASS)           // don't cache the results
            .setComment("Hello world!")                         // add a comment to the generated SQL
            .getResultList();
----

// Finally, a query method might return a `Pager`.
// This is an incubating API in Hibernate 6.3 that makes it easy to paginate query result sets.
// A query method returning type `Pager` must accept a `Page` object specifying the initial page.
//
// [source,java]
// ----
// @HQL("from Book where title like :title")
// Pager<Book> findBooksByTitle(String title, Page initialPage);
// ----
//
// There are several idioms for the use of `Pager`, here's one:
//
// [source,java]
// ----
// new Queries_(session)
//         .findBooksByTitle(title, Page.first(pageSize))
//                 .forEachRemainingPage(books -> {
//                     for (Book book : books) {
//                         ...
//                     }
//                     session.clear();
//                 })
// ----

An `insert`, `update`, or `delete` query must return `int`, `boolean`, or `void`.

[source,java]
----
@HQL("delete from Book")
int deleteAllBooks();
----

[source,java]
----
@HQL("update Book set discontinued = true where discontinued = false and isbn = :isbn")
boolean discontinueBook(String isbn);
----

[source,java]
----
@HQL("update Book set discontinued = true where isbn = :isbn")
void discontinueBook(String isbn);
----

On the other hand, finder methods are currently much more limited.
A finder method must return an entity type like `Book`, or a list of the entity type, `List<Book>`, for example.

[NOTE]
====
As you might expect, for a reactive session, all query methods and finder methods must return `Uni`.
====

// [[query-validator]]
// === An alternative approach
//
// :query-validator: https://github.com/hibernate/query-validator/
//
// What if you just don't like the ideas we've presented in this chapter, preferring to call the `Session` or `EntityManager` directly, but you still want compile-time validation for HQL?
// Or what if you _do_ like the ideas, but you're working on a huge existing codebase full of code you don't want to change?
//
// Well, there's a solution for you, too.
// The {query-validator}[Query Validator] is a separate annotation processor that's capable of type-checking HQL strings, not only in annotations, but even when they occur as arguments to `createQuery()`, `createSelectionQuery()`, or `createMutationQuery()`. It's even able to check calls to `setParameter()`, with some restrictions.
//
// The Query Validator works in `javac`, Gradle, Maven, and the Eclipse Java Compiler.
//
// [CAUTION]
// ====
// Unlike Hibernate Processor, which is a completely bog-standard Java annotation processor based on only standard Java APIs, the Query Validator makes use of internal compiler APIs in `javac` and `ecj`. This means it can't be guaranteed to work in every Java compiler. The current release is known to work in JDK 11 and above, though JDK 15 or above is preferred.
// ====

---

### Documentation Src Main Asciidoc Introduction Querying (`documentation/src/main/asciidoc/introduction/Querying.adoc`)

[[queries]]
== Executing queries

:hql: {doc-user-guide-url}#query-language

Hibernate features three complementary ways to write queries:

- the _Hibernate Query Language_, an extremely powerful superset of JPQL, which abstracts most of the features of modern dialects of SQL,
- the JPA _criteria query_ API, along with extensions, allowing almost any HQL query to be constructed programmatically via a typesafe API, and, of course
- for when all else fails, _native SQL_ queries.

In addition, Hibernate 7 provides a convenient new way to <<restrictions-and-ordering,programmatically customize>> a query before executing it.

[[hql-queries]]
=== HQL queries

:hql: {doc-user-guide-url}#query-language

A full discussion of the query language would require almost as much text as the rest of this Short Guide.
Fortunately, HQL is already described in exhaustive (and exhausting) detail in {doc-query-language-url}[_A Guide to Hibernate Query Language_].
It doesn't make sense to repeat that information here.
// The query language is discussed in great detail below in <<query-language>>.

Here we want to see how to execute a query via the `EntityAgent` or `EntityManager` API.
The method we call depends on what kind of query it is:

- _selection queries_ return a result list but do not modify the data, but
- _mutation statements_ modify data and return the number of modified rows.

Selection queries usually start with the keyword `select` or `from`, whereas mutation statements begin with the keyword `insert`, `update`, or `delete`.

.Executing HQL
[%breakable,cols="10,36,14,~"]
|===
| Kind | `EntityHandler` method | Interface | Execution method

| Selection | `createQuery(String,Class)` | `TypedQuery` | `getResultList()`, `getSingleResult()`, or `getSingleResultOrNull()`
| Mutation | `createStatement(String)` | `Statement` | `execute()`
|===

For example, to execute a selection query written in HQL, we might write:

[source,java]
----
List<Book> matchingBooks =
        entityManager.createQuery("from Book where title like :titlePattern", Book.class)
                     .setParameter("titlePattern", titleSearchPattern)
                     .getResultList();
----

// The main difference between `createSelectionQuery()` and `createQuery()` is that `createSelectionQuery()` throws an exception if passed a query string that begins with `insert`, `delete`, or `update`.

We've used `getResultList()` because we're expecting our query to return multiple results.
If we're expecting a query to return a single result, we can use `getSingleResult()`.

[source,java]
----
Book book =
        entityManager.createQuery("from Book where isbn = :isbn", Book.class)
                     .setParameter("isbn", isbn)
                     .getSingleResult();
----

Or, if we're expecting it to return at most one result, we can use `getSingleResultOrNull()`.

[source,java]
----
Book bookOrNull =
        entityManager.createQuery("from Book where isbn = :isbn", Book.class)
                     .setParameter("isbn", isbn)
                     .getSingleResultOrNull();
----

The difference, of course, is that `getSingleResult()` throws an exception if there's no matching row in the database, whereas `getSingleResultOrNull()` just returns `null`.

To execute a mutation statement, we use `execute()`, which returns the number of entities affected by the `insert`, `update`, or `delete`.

[source,java]
----
int deletedBooks =
        entityManager.createStatement("delete from Book where title like :titlePattern")
                     .setParameter("titlePattern", titleSearchPattern)
                     .execute();
----

The `setParameter()` methods specify arguments to query parameters.

[[query-parameters]]
=== Query parameters

Queries are often parameterized.

- In the query above, `:titleSearchPattern` is called a _named parameter_.
- Alternatively, we may label a parameter by a number. Such a parameter is called an _ordinal parameter_.

We may easily rewrite our query to use an ordinal parameter:

[source,java]
----
List<Book> matchingBooks =
        entityManager.createQuery("from Book where title like ?1", Book.class)
                     .setParameter(1, titleSearchPattern)
                     .getResultList();
----

When a query has multiple parameters, named parameters tend to be easier to read, even if slightly more verbose.

[WARNING]
// .Using parameters to avoid injection attacks
====
_Never_ concatenate user input with HQL and pass the concatenated string to `createQuery()` or `createStatement()`.
This would open up the possibility for an attacker to execute arbitrary code on your database server.
====

[TIP]
====
The two-argument forms of `setParameter()` are perfect for most purposes, but _very occasionally_ it's necessary to resolve an ambiguity in the interpretation of the argument value by explicitly specifying the <<compositional-basic-types,type>> of the argument.
The best way to identify the type is via a reference to a JPA metamodel `Type`.
There are two ways to do this:

// - by passing a Java `Class` as a third argument to link:{doc-javadoc-url}org/hibernate/query/CommonQueryContract.html#setParameter(java.lang.String,java.lang.Object,java.lang.Class)[`setParameter()`] (this doesn't usually help very much),
- by passing the `Type` as a third argument to `setParameter()`, or
- by packaging the argument and its `Type` in a `TypedParameterValue`.

For example, we may pass a <<static-metamodel,static metamodel>> reference to `setParameter()`.

[source,java]
----
entityManager.createQuery("from Person where address = :address")
             .setParameter("address" address, Person_.address.getType())
             .getResultList();
----
====

[[query-options]]
=== Query options

The `TypedQuery` and `Statement` interfaces provide a number of operations for controlling execution of a query or statement.

[source,java]
----
var recentPublications =
        entityAgent.createQuery("from Book where year(book) = year(local date)")
                   .ofType(Book.class)
                   .setTimeout(Timeout.ms(60_000))
                   .setQueryFlushMode(QueryFlushMode.NO_FLUSH)
                   .getResultList();
----

Even better JPA 4 provides for extension via query options and statement options
Hibernate defines several useful options in link:{doc-javadoc-url}/org/hibernate/query/QueryOption.html[QueryOption].

[source,java]
----
import org.hibernate.ReadOnlyMode;
import static org.hibernate.query.QueryOption.*;
...
var recentPublications =
        entityAgent.createQuery("from Book where year(book) = year(local date)")
                   .ofType(Book.class)
                   .addOption(new ResultSetCache("recent-publications"))
                   .addOption(new JdbcFetchSize(100))
                   .addOption(new Comment("Retrieve recent publications"))
                   .addOption(ReadOnlyMode.READ_ONLY)
                   .getResultList();
----

[[auto-flush]]
=== Auto-flush

By default, Hibernate dirty checks entities in the persistence context before executing a query, in order to determine if there are changes which have not yet been flushed to the database, but which might affect the results of the query.
If there are unflushed changes, then Hibernate goes ahead and executes an automatic <<flush,flush>> before executing the query.
That way, the query won't return stale results which fail to reflect changes made to data within the current unit of work.
But if there are many entities associated with the persistence context, then this can be an expensive operation.

To disable this behavior, set the query flush mode to `NO_FLUSH`:

[source,java]
----
Book bookOrNull =
        entityManager.createQuery("from Book where isbn = ?1", Book.class)
                     .setParameter(1, isbn)
                     .setQueryFlushMode(QueryFlushMode.NO_FLUSH)
                     .getSingleResult();
----

[CAUTION]
====
Setting the flush mode to `NO_FLUSH` might cause the query to return stale results.
====

Occasionally we need to build a query at runtime, from a set of optional conditions.
For this, JPA offers an API which allows programmatic construction of a query.

[[criteria-queries]]
=== Criteria queries

Imagine we're implementing some sort of search screen, where the user of our system is offered several different ways to constrain the query result set.
For example, we might let them search for books by title and/or the author name.
Of course, we could construct a HQL query by string concatenation, but this is a bit fragile, so it's quite nice to have an alternative.

[NOTE]
====
Actually, since Hibernate 6, every HQL query is compiled to a criteria query before being translated to SQL.
This ensures that the semantics of HQL and criteria queries are identical.
====

First, we need an object for building criteria queries.
Using the JPA-standard APIs, this would be a `CriteriaBuilder`, and we get it from the `EntityManagerFactory`:

[source,java]
----
CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder();
----

But in Hibernate, we can get something much better, a link:{doc-javadoc-url}org/hibernate/query/criteria/HibernateCriteriaBuilder.html[`HibernateCriteriaBuilder`]:

[source,java]
----
HibernateCriteriaBuilder builder =
        entityManagerFactory.unwrap(SessionFactory.class)
                .getCriteriaBuilder();
----

Or simply:

[source,java]
----
HibernateCriteriaBuilder builder =
        (HibernateCriteriaBuilder)
                entityManagerFactory.getCriteriaBuilder();
----

The `HibernateCriteriaBuilder` extends `CriteriaBuilder` and adds many operations available in HQL that JPQL doesn't have, including things like:

- window functions,
- common table expressions,
- lateral joins,
- derived tables,
- a wide range of built-in functions,
- and so on.

We're ready to create a simple criteria query.

[[criteria-query-example]]
[source,java]
----
CriteriaQuery<Book> query = builder.createQuery(Book.class);
Root<Book> book = query.from(Book.class);
Predicate where = builder.conjunction();
if (titlePattern != null) {
    where = builder.and(where, book.get(Book_.title).like(titlePattern));
}
if (namePattern != null) {
    Join<Book,Author> author = book.join(Book_.author);
    where = builder.and(where, author.get(Author_.name).like(namePattern));
}
query.select(book).where(where)
     .orderBy(book.get(Book_.title).asc());
----

Here, as before, the classes `Book_` and `Author_` are generated by <<metamodel-generator,Hibernate Processor>>.

Note that we've explicitly written in the static types of some objects here.
We wouldn't do that in real code.
Readability of criteria queries benefits quite a lot from the use of `var`.

.*Read more: why is the Criteria API so complicated?*
[%collapsible]
====
****
Unlike <<restrictions-and-ordering,restrictions>> in Hibernate or Jakarta Data, Criteria queries can have multiple root entities, and may join the same association multiple times.
That means that the Criteria API must reify each query root as an object and each join as an object.

A query root is an instance of `Root`:

[source,java]
Root<Book> book = query.from(Book.class);

A join is an instance of `Join`:

[source,java]
SetJoin<Book,Author> author = book.join(Book_.authors);

Now, to obtain an expression which can be used to restrict or order the query results, we usually need to resolve a reference to a persistent attribute _in the context_ of a given root or join:

[source,java]
TextExpression authorName = author.get(Author_.name)
TextExpression bookTitle = book.get(Book_.title);

Finally, we can express a restriction or ordering criterion in terms of expressions.

[source,java]
Predicate nameLikePattern = author.get(Author_.name).like(namePattern);
Order byTitle = book.get(Book_.title).asc();

If all this feels a bit overpowered for what you're trying to do, well, we feel ya.
We've addressed this objection both <<restrictions-and-ordering,in Hibernate>> and in Jakarta Data.
The restrictions API in Jakarta Data really is a pleasure to use.
Please try it out!
****
====

[NOTE]
// .Injection attacks and criteria queries
====
In the query above, we didn't bother treating `titlePattern` and `namePattern` as parameters.
That's safe because, by default, Hibernate automatically and transparently treats strings passed to the `CriteriaBuilder` as JDBC parameters.
====

Execution of a criteria query works almost exactly like execution of HQL.

.Executing criteria queries
[%breakable,cols="10,36,14,~"]
|===
| Kind | `EntityHandler` method | Interface | Execution method

| Selection | `createQuery(CriteriaQuery)` | `TypedQuery` | `getResultList()`, `getSingleResult()`, or `getSingleResultOrNull()`
| Mutation  |`createStatement(CriteriaStatement)` | `Statement` | `execute()`
|===

For example:

[source,java]
----
List<Book> matchingBooks =
        entityManager.createQuery(query)
                .getResultList();
----

Update, insert, and delete queries work similarly:

[source,java]
----
CriteriaDelete<Book> delete = builder.createCriteriaDelete(Book.class);
Root<Book> book = delete.from(Book.class);
delete.where(book.get(Book_.publicationDate).extract(LocalDateField.YEAR).lt(2000));
entityManager.createStatement(delete).execute();
----

It's even possible to transform a HQL query string to a criteria query, and modify the query programmatically before execution:
[source,java]
----
var builder = entityManagerFactory.getCriteriaBuilder();
var query =
        // transform HQL to criteria
        builder.createQuery(Book.class,
                "from Book where year(publicationDate) > 2000");

// modify the resulting criteria query
var root = (Root<Book>) query.getRootList().get(0);
query.where(root.get(Book_.title).like("Hibernate%"))
     .orderBy(root.get(Book_.title).asc(), root.get(Book_.isbn).desc());

// execute the modified query
List<Book> matchingBooks = entityManager.createQuery(query).getResultList();
----
This is starting to get a bit messy.
For problems like this, we can often use <<restrictions-and-ordering,`Restriction`>> instead.

[[criteria-definition]]
.*Read more: A more comfortable way to write criteria queries*
[%collapsible]
====
****
Do you find some of the code above a bit too verbose?
We do.

Actually, what makes the JPA criteria API less ergonomic than it should be is the need to call all operations of the `CriteriaBuilder` as instance methods, instead of having them as `static` functions.
The reason it works this way is that each JPA provider has its own implementation of `CriteriaBuilder`.

The helper class link:{doc-javadoc-url}org/hibernate/query/criteria/CriteriaDefinition.html[`CriteriaDefinition`] can reduce the verbosity of criteria queries by eliminating the need to explicitly qualify calls to the methods of `CriteriaBuilder`.
Our <<criteria-query-example,previous example>> would look like this:

[source,java]
----
CriteriaQuery<Book> query =
        new CriteriaDefinition(entityManagerFactory, Book.class) {{
            select(book);
            if (titlePattern != null) {
                restrict(book.get(Book_.title).like(titlePattern));
            }
            if (namePattern != null) {
                var author = book.join(Book_.author);
                restrict(author.get(Author_.name).like(namePattern));
            }
            orderBy(asc(book.get(Book_.title)));
        }};
----
****
====

When all else fails, and sometimes even before that, we're left with the option of writing a query in SQL.

[[native-queries]]
=== Native SQL queries

HQL is a powerful language that helps reduce the verbosity of SQL, and significantly increases the portability of queries between databases.
But ultimately, the true value of ORM is not in avoiding SQL, but in alleviating the pain involved in dealing with SQL result sets once we get them back to our Java program.
As we said <<orm-or-sql,right up front>>, Hibernate's generated SQL is meant to be used in conjunction with handwritten SQL, and native SQL queries are one of the facilities we provide to make that easy.

.Executing SQL
[%breakable,cols="10,36,14,~"]
|===
| Kind | `EntityHandler` method | Interface | Execution method

| Selection |  `createNativeQuery(String,Class)`, `createNativeQuery(String,ResultSetMapping)` | `TypedQuery` | `getResultList()`, `getSingleResult()`, or `getSingleResultOrNull()`
| Mutation | `createNativeStatement(String)` | `Statement` | `execute()`
| Stored procedure | `createStoredProcedureQuery(String)`, `createStoredProcedureQuery(String,Class...)` | `StoredProcedureQuery` | Various options (see Javadoc)
|===

For the most simple cases, Hibernate can infer the shape of the result set from the query result type we provide:

[source, java]
----
Book book =
        entityAgent.createNativeQuery("select * from Books where isbn = ?1", Book.class)
                   .setParameter(1, isbn)
                   .getSingleResult();

String title =
        entityAgent.createNativeQuery("select title from Books where isbn = ?1", String.class)
                   .setParameter(1, isbn)
                   .getSingleResult();
----

However, in general, there isn't enough information in the JDBC `ResultSetMetaData` to infer the mapping of columns to entity objects.
So for more complicated cases, we need to provide a JPA 4 `ResultSetMapping`.
There are two ways to do this:

- use the `@SqlResultSetMapping` annotation to define a named mapping, and pass the name or static metamodel reference to `createNativeQuery()`, or
- use the new `ResultSetMapping` framework to express the result set mapping in programmatic code.

The first option gets fairly messy, so we don't want to hurt your eyes by showing you an example of it.
The second option is more elegant:

[source,java]
----
import static jakarta.persistence.sql.ResultSetMapping.*;
...
var authorMapping =
         // mapping for the Author entity
         entity(Author.class,
				// mapping for a fields of Author
                field(Author_.ssn, "auth_ssn"),
				field(Author_.deceased, "auth_dead"),
				// mapping for an embedded object
                embedded(Author_.name,
						 // mappings for fields of Name embeddable
                         field(Name_.first, "auth_first_name"),
                         field(Name_.last, "auth_last_name")));
var authors =
        session.createNativeQuery(
                        """
                        select ssn as auth_ssn,
                               dead as auth_dead,
                               fname as auth_first_name,
                               lname as auth_last_name
                        from authors
                        """,
                        authorMapping)
               .getResultList();
----

Thanks to the use of the static metamodel, this code is very type safe.

// By default, Hibernate doesn't flush the session before execution of a native query.
// That's because the session is unaware of which modifications held in memory would affect the results of the query.
//
// So if there are any unflushed changes to ``Book``s, this query might return stale data:
//
// [source,java]
// ----
// List<Book> books =
//         entityAgent.createNativeQuery("select * from Books", Book.class)
//                    .getResultList();
// ----
//
// There's two ways to ensure the persistence context is flushed before this query is executed.
//
// Either, we could simply force a flush by calling `flush()` or by setting the flush mode to `FLUSH`:
//
// [source,java]
// ----
// List<Book> books =
//         entityAgent.createNativeQuery("select * from Books", Book.class)
//                    .setQueryFlushMode(FLUSH)
//                    .getResultList();
// ----
//
// Or, alternatively, we could tell Hibernate which modified state affects the results of the query:
//
// [source,java]
// ----
// List<Book> books =
//         entityAgent.createNativeQuery("select * from Books", Book.class)
//                    .unwrap(SelectionQuery.class)
//                    .addSynchronizedEntityClass(Book.class)
//                    .getResultList();
// ----

// [TIP]
// ====
// We can call stored procedures using `createStoredProcedureQuery()`.
// ====

[[restrictions-and-ordering]]
=== Restrictions and ordering

We've already seen how the JPA <<criteria-queries,Criteria Query API>> can be used to construct a query completely programmatically.
The Criteria API is powerful, but for the most common scenarios it's at least arguably overkill.
The <<criteria-definition,`CriteriaDefinition`>> class helps a bit, but it doesn't completely eliminate the verbosity of programmatic query definition.

Since Hibernate 7, there's a new option, a very ergonomic API for programmatically adding restrictions or ordering to an existing query before executing it.
(Actually, the ordering part of this was introduced in Hibernate 6.5.)
This new API:

- isn't part of the Criteria Query API, and so we don't need a `CriteriaQuery` object to make use of it,
- _does_ make use of the JPA <<metamodel-generator,static metamodel>> for type safety,
- works with both HQL and Criteria queries, and
- is optimized for the case of a query which returns its single root entity.

[source,java]
----
var selection =
        SelectionSpecification.create(Book.class,
            // an optional base query, written in HQL:
                "from Book where year(publicationDate) > 2000");

// add programmatic restrictions:
if (titlePattern != null)
    selection.restrict(Restriction.like(Book_.title, namePattern));
if (isbns != null && !isbns.isEmpty())
    selection.restrict(Restriction.in(Book_.isbn, isbns));

// add programmatic ordering:
if (orderByTitle) selection.sort(Order.asc(Book_.title));
if (orderByIsbn) selection.sort(Order.asc(Book_.isbn));

// add programmatic association fetching:
if (fetchPublisher) selection.fetch(Path.from(Book.class).to(Book_.publisher));

// execute the query in the given session:
List<Book> matchingBooks = selection.createQuery(entityAgent).getResultList();
----

Notice that:

- The link:{doc-javadoc-url}org/hibernate/query/restriction/Restriction.html[`Restriction`] interface has static methods for constructing a variety of different kinds of restriction in a completely typesafe way.
- Similarly, the link:{doc-javadoc-url}org/hibernate/query/Order.html[`Order`] interface has a variety of static methods for constructing different kinds of sorting criteria.

We need the following methods of link:{doc-javadoc-url}org/hibernate/query/programmatic/SelectionSpecification.html[`SelectionSpecification`]:

.Methods for query restriction and ordering
[%breakable,cols="20,~]
|===
| Method name | Purpose

| `restrict()` | Add a `Restriction` on the query results
| `sort()`, `resort()` | Specify how the query results should be ordered
| `fetch()` | Add a fetched association `Path`
| `augment()` | Add a custom function which directly manipulates the select query
|===

Two of these operations are also available for a link:{doc-javadoc-url}org/hibernate/query/programmatic/MutationSpecification.html[`MutationSpecification`]:

.Methods for mutation restriction
[%breakable,cols="20,~]
|===
| Method name | Purpose

| `restrict()` | Add a `Restriction` on the records to be updated
| `augment()` | Add a custom function which directly manipulates the update or delete query
|===

Alternatively, `Restriction` and `Order` can be used with <<paging-and-ordering,generated query or finder methods>>, and even with link:{doc-data-repositories-url}[Jakarta Data repositories].

The interface link:{doc-javadoc-url}org/hibernate/query/restriction/Path.html[`Path`] may be used to express restrictions on fields of an embedded or associated entity class.
It may even be used for association fetching.

[source,java]
----
List<Book> booksForPublisher =
        SelectionSpecification.create(Book.class)
                .restrict(Path.from(Book.class).to(Book_.publisher).to(Publisher_.name)
                                .equalTo(publisherName))
                .fetch(Path.from(Book.class).to(Book_.publisher))
                .createQuery(entityAgent)
                .getResultList();
----

Specifications aren't for everything, however.

[NOTE]
====
`SelectionSpecification` (similar to its friend `MutationSpecification`) may be used in cases where a query returns a single "root" entity, possibly with some fetched associations.
It's not useful in cases where a query should return multiple entities, a projection of entity fields, or an aggregation.
For such cases, the full Criteria API is appropriate.
====

Finally, the `augment()` method deserves its own subsection.

[[augmentation]]
=== Augmentation

When `Restriction`, `Path`, and `Order` aren't expressive enough, we can _augment_ the query by manipulating its representation as a criteria:

[source,java]
----
var books =
        SelectionSpecification.create(Book.class)
              .augment((builder, query, book) ->
                      // augment the query via JPA Criteria API
                      query.where(builder.like(book.get(Book_.title), titlePattern)))
                           .orderBy(builder.asc(book.get(Book_.isbn)))
              .createQuery(entityAgent)
              .getResultList();
----

For really advanced cases, `augment()` works quite nicely with <<criteria-definition,`CriteriaDefinition`>>.

[source,java]
----
var books =
        SelectionSpecification.create(Book.class)
              .augment((builder, query, book) ->
                  // eliminate explicit references to 'builder'
                  new CriteriaDefinition<>(query) {{
                      where(like(entity.get(BasicEntity_.title), titlePattern),
                            greaterThan(book.get(Book_.pages), minPages));
                      orderBy(asc(book.get(Book_.isbn)));
                  }}
              )
              .createQuery(entityAgent)
              .getResultList();
----

However, we emphasize that this API shines in cases where complex manipulations are _not_ required.
For complicated queries involving multiple entities, or with aggregation and projection, you're best off heading straight to the `CriteriaBuilder`.

Programmatic restrictions, and especially programmatic ordering, are often used together with pagination.

[[pagination]]
=== Limits and pagination

If a query might return more results than we can handle at one time, we may specify:

- a _limit_ on the maximum number of rows returned, and,
- optionally, an _offset_, the first row of an ordered result set to return.

[TIP]
====
The offset is used to paginate query results.
====

There's two ways to add a limit or offset to a HQL or native SQL query:

- using the syntax of the query language itself, for example, `offset 10 rows fetch next 20 rows only`, or
- using the methods `setFirstResult()` and `setMaxResults()` of the `SelectionQuery` interface.

If the limit or offset is parameterized, the second option is simpler.
For example, this:

[source,java]
----
List<Book> books =
        entityAgent.createQuery("from Book where title like ?1 order by title", Book.class)
                   .setParameter(1, titlePattern)
                   .setMaxResults(MAX_RESULTS)
                   .getResultList();
----

is simpler than:

[source,java]
----
// a worse way to do pagination
List<Book> books =
        entityAgent.createQuery("from Book where title like ?1 order by title fetch first ?2 rows only", Book.class)
                   .setParameter(1, titlePattern)
                   .setParameter(2, MAX_RESULTS)
                   .getResultList();
----

Hibernate's `SelectionQuery` has a slightly different way to paginate the query results:

[source,java]
----
List<Book> books =
        entityAgent.createQuery("from Book where title like ?1 order by title", Book.class)
                   .setParameter(1, titlePattern)
                   .unwrap(SelectionQuery.class)
                   .setPage(Page.first(MAX_RESULTS))
                   .getResultList();
----

The `getResultCount()` method is useful for displaying the number of pages of results:

[source,java]
----
var query =
        entityAgent.createQuery("from Book where title like ?1 order by title", Book.class)
                   .setParameter(1, titlePattern);
long results = query.getResultCount();
long pages = results / MAX_RESULTS + (results % MAX_RESULTS == 0 ? 0 : 1);
List<Book> books = query.setMaxResults(MAX_RESULTS).getResultList();
----

.Methods for query limits and pagination
[%breakable,cols="30,~,^15"]
|===
| Method name | Purpose | JPA-standard

| `setMaxResults()` | Set a limit on the number of results returned by a query | &#10004;
| `setFirstResult()` | Set an offset on the results returned by a query | &#10004;
| `setPage()` | Set the limit and offset by specifying a `Page` object | &#10006;
| `getResultCount()` | Determine how many results the query would return in the absence of any limit or offset | &#10004;
|===

// It's quite common for pagination to be combined with the need to order query results by a field that's determined at runtime.
// The `Order` class we just met <<restrictions-and-ordering,above>> provides the ability to specify that the query results should be ordered by one or more fields of the entity type returned by the query:
//
// [[query-order-example]]
// [source,java]
// ----
// List<Book> books =
//         session.createSelectionQuery("from Book where title like ?1", Book.class)
//             .setParameter(1, titlePattern)
//             .setOrder(List.of(Order.asc(Book_.title), Order.asc(Book_.isbn)))
//             .setMaxResults(MAX_RESULTS)
//             .getResultList();
// ----

The approach to pagination we've just seen is sometimes called _offset-based pagination_.
Since Hibernate 6.5, there's an alternative approach, which offers some advantages, though it's a little more difficult to use.

[[key-based-pagination]]
=== Key-based pagination

_Key-based pagination_ aims to reduce the likelihood of missed or duplicate results when data is modified between page requests.
It's most easily illustrated with an example:

[source,java]
----
String QUERY = "from Book where publicationDate > :minDate";

// obtain the first page of results
KeyedResultList<Book> first =
        entityAgent.createQuery(QUERY, Book.class)
                   .setParameter("minDate", minDate)
                   .unwrap(SelectionQuery.class)
                   .getKeyedResultList(Page.first(25)
                           .keyedBy(Order.asc(Book_.isbn)));
List<Book> firstPage = first.getResultList();
...

if (!firstPage.isLastPage()) {
    // obtain the second page of results
    KeyedResultList<Book> second =
            entityAgent.createQuery(QUERY, Book.class)
                       .setParameter("minDate", minDate)
                       .unwrap(SelectionQuery.class)
                       .getKeyedResultList(firstPage.getNextPage());
    List<Book> secondPage = second.getResultList();
    ...
}
----

The "key" in key-based pagination refers to a unique key of the result set which determines a total order on the query results.
In this example, `Book.isbn` is the key.

Since this code is a little bit fiddly, key-based pagination works best with <<key-based-paging,generated query or finder methods>>.

[[projection-lists]]
=== Representing projection lists

A _projection list_ is the list of things that a query returns, that is, the list of expressions in the `select` clause.
Since Java has no tuple types, representing query projection lists in Java has always been a problem for JPA and Hibernate.
Traditionally, we've just used `Object[]` most of the time:

[source,java]
----
var results =
        entityAgent.createQuery("select isbn, title from Book", Object[].class)
                   .getResultList();

for (var result : results) {
    var isbn = (String) result[0];
    var title = (String) result[1];
    ...
}
----

This is really a bit ugly.
Java's `record` types now offer an interesting alternative:

[source,java]
----
record IsbnTitle(String isbn, String title) {}

var results =
        entityAgent.createQuery("select isbn, title from Book", IsbnTitle.class)
                   .getResultList();

for (var result : results) {
    var isbn = result.isbn();
    var title = result.title();
    ...
}
----
Notice that we're able to declare the `record` right before the line which executes the query.

This works just as well with queries written in SQL:

[source,java]
----
record BookInfo(String isbn, String title, int pages) {}

List<BookInfo> resultList =
        entityAgent.createNativeQuery("select isbn, title, pages from Book", BookInfo.class)
                   .getResultList();
----

Now, this approach is only _superficially_ more typesafe, since the query itself is not checked statically, and so we can't say it's objectively better.
But perhaps you find it more aesthetically pleasing.
And if we're going to be passing query results around the system, the use of a `record` type is _much_ better.

The criteria query API offers a much more satisfying solution to the problem.
Consider the following code:

[source,java]
----
var builder = sessionFactory.getCriteriaBuilder();
var query = builder.createTupleQuery();
var book = query.from(Book.class);
var bookTitle = book.get(Book_.title);
var bookIsbn = book.get(Book_.isbn);
var bookPrice = book.get(Book_.price);
query.select(builder.tuple(bookTitle, bookIsbn, bookPrice));
var resultList = entityAgent.createQuery(query).getResultList();
for (var result : resultList) {
    String title = result.get(bookTitle);
    String isbn = result.get(bookIsbn);
    BigDecimal price = result.get(bookPrice);
    ...
}
----

This code is manifestly completely typesafe, and much better than we can hope to do with HQL.

[[named-queries]]
=== Named queries

The `@NamedQuery` and `@NamedStatement` annotations let us define a HQL query or statement that's compiled and checked as part of the bootstrap process.
This means we find out about errors in our queries earlier, instead of waiting until the query is actually executed.
We can place the annotation on any class, even on an entity class.

[source,java]
----
@NamedQuery(name = "10BooksByTitle",
        query =
            """
            from Book
            where title like :titlePattern
            order by title
            fetch first 10 rows only
            """)
class BookQueries {}
----

We have to make sure that the class with the `@NamedQuery` annotation will be scanned by Hibernate, either:

- by adding `<class>org.hibernate.example.BookQueries</class>` to `persistence.xml`, or
- by calling `persistenceConfiguration.managedClass(BookQueries.class)`.

Alternatively, the `@NamedQuery` annotation can be placed on a package or module descriptor.
If we declare a named query at the package or module level, we must call:

[source,java]
----
configuration.addPackage("org.hibernate.example")
// or
configuration.addModule("org.hibernate-example")
----
so that Hibernate knows where to find it.

[TIP]
====
It's nice to have our queries checked at startup time.
It's even better to have them checked at compile time.
Hibernate Processor can do that for us, with the help of the link:{doc-javadoc-url}org/hibernate/annotations/processing/CheckHQL.html[`@CheckHQL`] annotation, and that's a really good reason to use `@NamedQuery` and `@NamedStatement`.
====

The `@NamedNativeQuery` and `@NamedNativeStatement`  annotations let us do something similar with native SQL queries.
Like `@NamedQuery`, they may be placed on a package or module descriptor.
But there's much less advantage to using `@NamedNativeQuery`, because there's very little Hibernate can do to validate the correctness of a query written in the native SQL dialect of your database.

Whether it's written in HQL or SQL, we execute our named query like this:

[source,java]
----
List<Book> books =
        entityManager.createQuery(BookQueries_._10BooksByTitle_)
                     .setParameter("titlePattern", titlePattern)
                     .getResultList();
----

Here, `BookQueries_.\_10BooksByTitle_` is an element of the JPA static metamodel of type `TypedQueryReference<Book>`, generated by Hibernate Processor.
We're going to learn more about Hibernate Processor in the next chapter.

.Executing named queries
[%breakable,cols="10,12,36,14,~"]
|===
| Kind | Annotations | `EntityHandler` method | Interface | Execution method

| Selection | `@NamedQuery`, `@NamedNativeQuery` | `createQuery(TypedQueryReference)`, `createNamedQuery(String,Class)` | `TypedQuery` | `getResultList()`, `getSingleResult()`, `getSingleResultOrNull()`
| Mutation | `@NamedStatement`, `@NamedNativeStatement` | `createStatement(Statemen tReference)`, `createNamedStatement(String)` | `Statement` | `execute()`
|===

Note that the code which executes the named query is not aware of whether the query was written in HQL or in native SQL, making it slightly easier to change and optimize the query later.

// [TIP]
// ====
// :query-validator: https://github.com/hibernate/query-validator/
//
// Actually, Hibernate even has a separate <<query-validator,Query Validator>> capable of performing compile-time validation of HQL query strings that occur as arguments to `createQuery()` and friends.
// If we use the Query Validator, there's not much advantage to the use of named queries.
// ====

---

### Documentation Src Main Asciidoc Introduction Tuning (`documentation/src/main/asciidoc/introduction/Tuning.adoc`)

[[tuning-and-performance]]
== Tuning and performance

Once you have a program up and running using Hibernate to access
the database, it's inevitable that you'll find places where performance is
disappointing or unacceptable.

Fortunately, most performance problems are relatively easy to solve with
the tools that Hibernate makes available to you, as long as you keep a
couple of simple principles in mind.

First and most important: the reason you're using Hibernate is
that it makes things easier. If, for a certain problem, it's making
things _harder_, stop using it. Solve this problem with a different tool
instead.

IMPORTANT: Just because you're using Hibernate in your program doesn't mean
you have to use it _everywhere_.

Second: there are two main potential sources of performance bottlenecks in
a program that uses Hibernate:

- too many round trips to the database, and
- memory consumption associated with the first-level (session) cache.

So performance tuning primarily involves reducing the number of accesses
to the database, and/or controlling the size of the session cache.

But before we get to those more advanced topics, we should start by tuning
the connection pool.

[[connection-pool]]
=== Tuning the connection pool

The connection pool built in to Hibernate is suitable for testing, but isn't intended for use in production.
Instead, Hibernate supports several different connection pools, including our favorite, Agroal.

Hibernate will automatically make use of `AgroalConnectionProvider` if the module `org.hibernate.orm:hibernate-agroal` is available at runtime.
So just add it as a runtime dependency, and you're all set.

Well, actually, that's a bit fragile, since Hibernate silently falls back to using the default connection pool if Agroal happens to be missing at runtime.
Perhaps it's better to set this configuration property:

[%breakable,cols="37,~"]
|===
| Configuration property name | Purpose

| link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#CONNECTION_PROVIDER[`hibernate.connection.provider_class`] | Explicitly specify a link:{doc-javadoc-url}/org/hibernate/engine/jdbc/connections/spi/ConnectionProvider.html[connection pool], for example, `agroal`, `hikaricp` or `c3p0`.
|===

TIP: You can set `hibernate.connection.provider_class` to `agroal` so that Hibernate fails at startup if Agroal is missing.


To properly configure Agroal, you'll need to set some extra configuration properties, in addition to the settings we already saw in <<basic-configuration-settings>>.
Properties with the prefix `hibernate.agroal` are passed through to Agroal:

[source,properties]
----
# configure Agroal connection pool
hibernate.agroal.maxSize 20
hibernate.agroal.minSize 10
hibernate.agroal.acquisitionTimeout PT1s
hibernate.agroal.reapTimeout PT10s
----

There are many to choose from, as enumerated by link:{doc-javadoc-url}/org/hibernate/cfg/AgroalSettings.html[`AgroalSettings`]:

.Settings for configuring Agroal
[%breakable,cols="37,~"]
|===
| Configuration property name | Purpose

| `hibernate.agroal.maxSize` | The maximum number of connections present on the pool
| `hibernate.agroal.minSize` | The minimum number of connections present on the pool
| `hibernate.agroal.initialSize` | The number of connections added to the pool when it is started
| `hibernate.agroal.maxLifetime` | The maximum amount of time a connection can live, after which it is removed from the pool
| `hibernate.agroal.acquisitionTimeout` | The maximum amount of time a thread can wait for a connection, after which an exception is thrown instead
| `hibernate.agroal.reapTimeout` | The duration for eviction of idle connections
| `hibernate.agroal.leakTimeout` | The duration of time a connection can be held without causing a leak to be reported
| `hibernate.agroal.idleValidation` | A foreground validation is executed if a connection has been idle on the pool for longer than this duration
| `hibernate.agroal.validationTimeout` | The interval between background validation checks
| `hibernate.agroal.initialSql` | A SQL command to be executed when a connection is created
|===

The following settings are common to all connection pools supported by Hibernate:

.Common settings for connection pools
[%breakable,cols="37,~"]
|===
| link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#POOL_SIZE[`hibernate.connection.pool_size`] | The size of the connection pool
| link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#AUTOCOMMIT[`hibernate.connection.autocommit`] | The default autocommit mode
| link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#ISOLATION[`hibernate.connection.isolation`] | The default transaction isolation level
|===

:hikaricp: https://github.com/brettwooldridge/HikariCP

A popular alternative to Agroal is {hikaricp}[HikariCP].
Integration with HikariCP is provided by the module `org.hibernate.orm:hibernate-hikaricp`.
Its settings are enumerated by link:{doc-javadoc-url}/org/hibernate/cfg/HikariCPSettings.html[`HikariCPSettings`].

[NOTE]
====
In a container environment, you usually don't need to configure a connection pool through Hibernate.
Instead, you'll use a container-managed datasource, as we saw in <<basic-configuration-settings>>.
====

A related important setting is the default JDBC fetch size.

[[jdbc-fetch-size]]
=== JDBC fetch size

The _JDBC fetch size_ controls the maximum number of rows the JDBC driver fetches from the database in one round trip.
In Hibernate we usually limit query result sets using <<pagination,pagination>>, and so we almost always prefer that the JDBC driver fetch the whole query result set in one trip.
Most JDBC drivers accommodate this usage pattern by _not_ setting a default fetch size.
However, there are a couple of exceptions to this and for the offending drivers you should probably override the default fetch size using the following configuration property.

.Default JDBC fetch size
[%autowidth.stretch]
|===
| Configuration property name | Purpose | Alternative option

| link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#STATEMENT_FETCH_SIZE[`hibernate.jdbc.fetch_size`] | The default JDBC fetch size  | link:{doc-javadoc-url}/org/hibernate/query/QueryOption.JdbcFetchSize.html[JdbcFetchSize]
|===

The default fetch size can be overridden for a given query by using the link:{doc-javadoc-url}/org/hibernate/query/QueryOption.JdbcFetchSize.html[`JdbcFetchSize`] option, but this is rarely necessary.

[WARNING]
====
The Oracle JDBC driver defaults to a JDBC fetch size of 10.
You should _always_ set `hibernate.jdbc.fetch_size` explicitly if you're using Oracle, or, even better, specify the parameter `defaultRowPrefetch` in the JDBC connection URL.
====

[TIP]
====
The MySQL JDBC driver ignores the fetch size by default.
The JDBC connection property `useCursorFetch=true` enables the use of server-side cursors, and with this setting the driver respects the fetch size.
====

[[statement-batching]]
=== Enabling statement batching

An easy way to improve performance of some transactions, with almost no work at all, is to turn on automatic DML statement batching.
Batching only helps in cases where a program executes many inserts, updates, or deletes against the same table in a single transaction.

All we need to do is set a single property:

.Enabling JDBC batching
[%autowidth.stretch]
|===
| Configuration property name | Purpose | Alternative option

| link:{doc-javadoc-url}/org/hibernate/cfg/BatchSettings.html#STATEMENT_BATCH_SIZE[`hibernate.jdbc.batch_size`] | Maximum batch size for SQL statement batching | link:{doc-javadoc-url}/org/hibernate/SessionCreationOption.JdbcBatchSize.html[JdbcBatchSize]
|===

To confirm that statement batching is working, enable ``TRACE``-level logging for the category `org.hibernate.orm.jdbc.batch`.

That said, batching is rarely the most convenient or most efficient way to update or delete many rows at once.

[TIP]
====
Even better than DML statement batching is the use of HQL `update` or `delete` queries, or even native SQL that calls a stored procedure!
====

[[association-fetching]]
=== Association fetching

:association-fetching: {doc-user-guide-url}#fetching

Achieving high performance in ORM means minimizing the number of round trips to the database. This goal should be uppermost in your mind whenever you're writing data access code with Hibernate. The most fundamental rule of thumb in ORM is:

- explicitly specify all the data you're going to need right at the start of a session/transaction, and fetch it immediately in one or two queries,
- and only then start navigating associations between persistent entities.

image::images/fetching.png[Fetching process,width=700,align="center"]

Without question, the most common cause of poorly-performing data access code in Java programs is the problem of _N+1 selects_.
Here, a list of _N_ rows is retrieved from the database in an initial query, and then associated instances of a related entity are fetched using _N_ subsequent queries.

[IMPORTANT]
// .This problem is your responsibility
====
This isn't a bug or limitation of Hibernate; this problem even affects typical handwritten JDBC code behind DAOs.
Only you, the developer, can solve this problem, because only you know ahead of time what data you're going to need in a given unit of work.
But that's OK.
Hibernate gives you all the tools you need.
====

In this section we're going to discuss different ways to avoid such "chatty" interaction with the database.

Hibernate provides several strategies for efficiently fetching associations and avoiding _N+1_ selects:

- _outer join fetching_ -- where an association is fetched using a `left outer join`,
- _batch fetching_ -- where an association is fetched using a subsequent `select` with a batch of primary keys, and
- _subselect fetching_ -- where an association is fetched using a subsequent `select` with keys re-queried in a subselect.

Of these, you should almost always use outer join fetching.
But let's consider the alternatives first.

[[batch-subselect-fetch]]
=== Batch fetching and subselect fetching

Consider the following code:

[source,java]
----
List<Book> books =
        entityManager.createQuery("from Book order by isbn")
            .ofType(Book.class)
            .getResultList();
books.forEach(book -> book.getAuthors().forEach(author -> out.println(book.title + " by " + author.name)));
----

This code is _very_ inefficient, resulting, by default, in the execution of _N+1_ `select` statements, where _N_ is the number of ``Book``s.

Let's see how we can improve on that.

[discrete]
===== SQL for batch fetching

With batch fetching enabled, Hibernate might execute the following SQL on PostgreSQL:

[source,sql]
----
/* initial query for Books */
select b1_0.isbn,b1_0.price,b1_0.published,b1_0.publisher_id,b1_0.title
from Book b1_0
order by b1_0.isbn

/* first batch of associated Authors */
select a1_0.books_isbn,a1_1.id,a1_1.bio,a1_1.name
from Book_Author a1_0
    join Author a1_1 on a1_1.id=a1_0.authors_id
where a1_0.books_isbn = any (?)

/* second batch of associated Authors */
select a1_0.books_isbn,a1_1.id,a1_1.bio,a1_1.name
from Book_Author a1_0
    join Author a1_1 on a1_1.id=a1_0.authors_id
where a1_0.books_isbn = any (?)
----

The first `select` statement queries and retrieves ``Book``s.
The second and third queries fetch the associated ``Author``s in batches.
The number of batches required depends on the configured _batch size_.
Here, two batches were required, so two SQL statements were executed.

[NOTE]
====
The SQL for batch fetching looks slightly different depending on the database.
Here, on PostgreSQL, Hibernate passes a batch of primary key values as a SQL `ARRAY`.
====

[discrete]
===== SQL for subselect fetching

On the other hand, with subselect fetching, Hibernate would execute this SQL:

[source,sql]
----
/* initial query for Books */
select b1_0.isbn,b1_0.price,b1_0.published,b1_0.publisher_id,b1_0.title
from Book b1_0
order by b1_0.isbn

/* fetch all associated Authors */
select a1_0.books_isbn,a1_1.id,a1_1.bio,a1_1.name
from Book_Author a1_0
    join Author a1_1 on a1_1.id=a1_0.authors_id
where a1_0.books_isbn in (select b1_0.isbn from Book b1_0)
----

Notice that the first query is re-executed in a subselect in the second query.
The execution of the subselect is likely to be relatively inexpensive, since the data should already be cached by the database.
Clever, huh?

[discrete]
===== Enabling the use of batch or subselect fetching

Both batch fetching and subselect fetching are disabled by default, but we may enable one or the other globally using properties.

.Configuration settings to enable batch and subselect fetching
// [%breakable,cols="32,~,14,14"]
[%breakable]
|===
| Configuration property name | Property value | Session option | Fetch option

| `hibernate.default_batch_fetch_size`
| A sensible batch size `>1` to enable batch fetching
| link:{doc-javadoc-url}/org/hibernate/SessionCreationOption.FetchBatchSize.html[`FetchBatchSize`] | `BatchSize`
// | `@Fetch(batchSize=10)`, `@BatchSize(10)`
| `hibernate.use_subselect_fetch`
| `true` to enable subselect fetching
| link:{doc-javadoc-url}/org/hibernate/SessionCreationOption.PreferredFetchMethod.html[`PreferredFetchMethod.BY_SUBQUERY`] | link:{doc-javadoc-url}/org/hibernate/FetchMethod.html#BY_SUBQUERY[`FetchMethod.BY_SUBQUERY`]
// | `@Fetch(SUBSELECT)`
|===

A global setting is a blunt instrument, and typically we need more granular control over fetching.
One alternative is to enable batch or subselect fetching in a given session, using a session creation option defined by Hibernate:

[source,java]
----
import org.hibernate.SessionCreationOption.FetchBatchSize;
...
var entityManager =
        // create a session with batch fetching enabled
        entityManagerFactory.createEntityManager(new FetchBatchSize(5));
----
[source,java]
----
import org.hibernate.SessionCreationOption.PreferredFetchMethod;
...
var entityManager =
        // create a session with subselect fetching enabled
        entityManagerFactory.createEntityManager(PreferredFetchMethod.BY_SUBQUERY);
----

// [source,java]
// ----
// session.setFetchBatchSize(5);
// session.setSubselectFetchingEnabled(true);
// ----

But this approach is probably still not granular enough.

Since JPA 4, the best way to make use of batch or subselect fetching is via an <<entity-graph,entity graph>>.
JPA provides a standard `FetchOption` for batch fetching:

[source,java]
----
import jakarta.persistence.BatchFetch;
...
var graph = entityManager.createEntityGraph(Book.class);
graph.addAttributeNode(Book_.authors)
     .addOption(new BatchFetch(5));
Book book = entityManager.find(graph, bookId);
----

Hibernate defines a custom `FetchOption` which allows more direct choice of association fetching strategy:

[source,java]
----
import org.hibernate.FetchMethod;
....
var graph = entityManager.createEntityGraph(Book.class);
graph.addAttributeNode(Book_.authors)
     .addOption(FetchMethod.BY_SUBQUERY);
Book book = entityManager.find(graph, bookId);
----

Note that link:{doc-javadoc-url}/org/hibernate/FetchMethod.html#BY_SUBQUERY[`FetchMethod.BY_SUBQUERY`] has the same effect as `FetchMethod.BY_ID`, except after execution of a HQL or criteria query.
But after query execution, `BY_SUBQUERY` is able to much more efficiently fetch associations.


// [%unbreakable]
// [TIP]
// ====
// We may request subselect fetching even more selectively by annotating a collection or association with the link:{doc-javadoc-url}/org/hibernate/annotations/Fetch.html[`@Fetch`] annotation.
// [source,java]
// ----
// @ManyToMany @Fetch(SUBSELECT)
// Set<Author> authors;
// ----
// Note that `@Fetch(SUBSELECT)` has the same effect as `@Fetch(SELECT)`, except after execution of a HQL or criteria query.
// But after query execution, `@Fetch(SUBSELECT)` is able to much more efficiently fetch associations.
// ====

That's all there is to it.
Too easy, right?

Sadly, that's not the end of the story.
While batch fetching might _mitigate_ problems involving N+1 selects, it won't solve them.
The truly correct solution is to fetch associations using joins.
Batch fetching (or subselect fetching) can only be the _best_ solution in rare cases where outer join fetching would result in a cartesian product and a huge result set.

But batch fetching and subselect fetching have one important characteristic in common: they can be performed _lazily_.
This is, in principle, pretty convenient.
When we query data, and then navigate an object graph, lazy fetching saves us the effort of planning ahead.
It turns out that this is a convenience we're going to have to surrender.

[[join-fetch]]
=== Join fetching

Outer join fetching is usually the best way to fetch associations, and it's what we use most of the time.
Unfortunately, by its very nature, join fetching simply can't be lazy.
So to make use of join fetching, we must plan ahead.
Our general advice is:

TIP: Avoid the use of lazy fetching, which is often the source of N+1 selects.

Now, we're not saying that associations should be mapped for eager fetching by default!
That would be a terrible idea, resulting in simple session operations that fetch almost the entire database.
Therefore:

TIP: Most associations should be mapped for lazy fetching by default.

It sounds as if this tip is in contradiction to the previous one, but it's not.
It's saying that you must explicitly specify eager fetching for associations precisely when and where they are needed.

If we need eager join fetching in some particular transaction, we have four different ways to specify that.

[cols="40,~"]
|===
| Passing a JPA `EntityGraph` | We've already seen this in <<entity-graph>>
| Specifying a named _fetch profile_ | We'll discuss this approach later in <<fetch-profiles>>
| Using `left join fetch` in HQL/JPQL | See {doc-query-language-url}[_A Guide to Hibernate Query Language_] for details
| Using `From.fetch()` in a criteria query | Same semantics as `join fetch` in HQL
|===

Typically, a query is the most convenient option.
Here's how we can ask for join fetching in HQL:

[source,java]
----
List<Book> booksWithJoinFetchedAuthors =
        entityAgent.createQuery("from Book left join fetch authors order by isbn")
            .ofType(Book.class)
            .getResultList();
----

And this is the same query, written using the criteria API:

[source,java]
----
var builder = sessionFactory.getCriteriaBuilder();
var query = builder.createQuery(Book.class);
var book = query.from(Book.class);
book.fetch(Book_.authors, JoinType.LEFT);
query.select(book);
query.orderBy(builder.asc(book.get(Book_.isbn)));
List<Book> booksWithJoinFetchedAuthors =
        entityAgent.createQuery(query).getResultList();
----

Either way, a single SQL `select` statement is executed:

[source,sql]
----
select b1_0.isbn,a1_0.books_isbn,a1_1.id,a1_1.bio,a1_1.name,b1_0.price,b1_0.published,b1_0.publisher_id,b1_0.title
from Book b1_0
    join (Book_Author a1_0 join Author a1_1 on a1_1.id=a1_0.authors_id)
        on b1_0.isbn=a1_0.books_isbn
order by b1_0.isbn
----

Much better!

Join fetching, despite its non-lazy nature, is clearly more efficient than either batch or subselect fetching, and this is the source of our recommendation to avoid the use of lazy fetching.

[TIP]
====
There's one interesting case where join fetching becomes inefficient: when we fetch two many-valued associations _in parallel_.
Imagine we wanted to fetch both `Author.books` and `Author.royaltyStatements` in some unit of work.
Joining both collections in a single query would result in a cartesian product of tables, and a large SQL result set.
Subselect fetching comes to the rescue here, allowing us to fetch `books` using a join, and `royaltyStatements` using a single subsequent `select`.
====

Of course, an alternative way to avoid many round trips to the database is to cache the data we need in the Java client.
If we're expecting to find the associated data in a local cache, we probably don't need join fetching at all.

[TIP]
====
But what if we can't be _certain_ that all associated data will be in the cache?
In that case, we might be able to reduce the cost of cache misses by enabling batch fetching.
====

[[second-level-cache]]
=== The second-level cache

:second-level-cache: {doc-user-guide-url}#caching

A classic way to reduce the number of accesses to the database is to use a second-level cache, allowing  data cached in memory to be shared between sessions.

By nature, a second-level cache tends to undermine the ACID properties of transaction processing in a relational database.
We _don't_ use a distributed transaction with two-phase commit to ensure that changes to the cache and database happen atomically.
So a second-level cache is often by far the easiest way to improve the performance of a system, but only at the cost of making it much more difficult to reason about concurrency.
And so the cache is a potential source of bugs which are difficult to isolate and reproduce.

Therefore, by default, an entity is not eligible for storage in the second-level cache.
We must explicitly mark each entity that will  be stored in the second-level cache with the link:{doc-javadoc-url}/org/hibernate/annotations/Cache.html[`@Cache`] annotation from `org.hibernate.annotations`.

But that's still not enough.
Hibernate does not itself contain an implementation of a second-level cache, so it's also necessary to configure an external _cache provider_.

[CAUTION]
// .Caching is disabled by default
====
Caching is disabled by default.
To minimize the risk of data loss, we force you to stop and think before any entity goes into the cache.
====

Hibernate segments the second-level cache into named _regions_, one for each:

- mapped entity hierarchy or
- collection role.

For example, there might be separate cache regions for `Author`, `Book`, `Author.books`, and `Book.authors`.

Each region is permitted its own policies for expiry, persistence, and replication. These policies must be configured externally to Hibernate.

The appropriate policies depend on the kind of data an entity represents. For example, a program might have different caching policies for "reference" data, for transactional data, and for data used for analytics. Ordinarily, the implementation of those policies is the responsibility of the underlying cache implementation.

[WARNING]
====
The second-level cache is never aware of any changes to data which are made externally to Hibernate.
Updates made via direct JDBC--or by some other program--are never visible in the second-level cache.
When such updates occur, we might need to <<second-level-cache-management,explicitly invalidate cached data>>.
Alternatively, in cases where the program is able to tolerate somewhat stale data, an expiry policy might be an acceptable solution.
====

[[enable-second-level-cache]]
=== Specifying which data is cached

By default, no data is eligible for storage in the second-level cache.

An entity hierarchy or collection role may be assigned a region using the `@Cache` annotation.
If no region name is explicitly specified, the region name is just the name of the entity class or collection role.

[source,java]
----
@Entity
@Cache(usage=NONSTRICT_READ_WRITE, region="Publishers")
class Publisher {
    ...

    @Cache(usage=READ_WRITE, region="PublishedBooks")
    @OneToMany(mappedBy=Book_.PUBLISHER)
    Set<Book> books;

    ...
}
----

The cache defined by a `@Cache` annotation is automatically utilized by Hibernate to:

- retrieve an entity by id when `find()` is called, or
- to resolve an association by id.

[WARNING]
====
The `@Cache` annotation must be specified on the _root class_ of an entity inheritance hierarchy.
It's an error to place it on a subclass entity.
====

The `@Cache` annotation always specifies a link:{doc-javadoc-url}org/hibernate/annotations/CacheConcurrencyStrategy.html[`CacheConcurrencyStrategy`], a policy governing access to the second-level cache by concurrent transactions.

.Cache concurrency
[%breakable,cols="20,30,~"]
|===
| Concurrency policy | Interpretation | Explanation

| `READ_ONLY` a|
- Immutable data
- Read-only access
| Indicates that the cached object is immutable, and is never updated. If an entity with this cache concurrency is updated, an exception is thrown.

This is the simplest, safest, and best-performing cache concurrency strategy. It's particularly suitable for so-called "reference" data.

| `NONSTRICT_READ_WRITE` a|
- Concurrent updates are extremely improbable
- Read/write access with no locking
| Indicates that the cached object is sometimes updated, but that it's extremely unlikely that two transactions will attempt to update the same item of data at the same time.

This strategy does not use locks. When an item is updated, the cache is invalidated both before and after completion of the updating transaction. But without locking, it's impossible to completely rule out the possibility of a second transaction storing or retrieving stale data in or from the cache during the completion process of the first transaction.

| `READ_WRITE` a|
- Concurrent updates are possible but not common
- Read/write access using soft locks
a| Indicates a non-vanishing likelihood that two concurrent transactions attempt to update the same item of data simultaneously.

This strategy uses "soft" locks to prevent concurrent transactions from retrieving or storing a stale item from or in the cache during the transaction completion process. A soft lock is simply a marker entry placed in the cache while the updating transaction completes.

- A second transaction may not read the item from the cache while the soft lock is present, and instead simply proceeds to read the item directly from the database, exactly as if a regular cache miss had occurred.
- Similarly, the soft lock also prevents this second transaction from storing a stale item to the cache when it returns from its round trip to the database with something that might not quite be the latest version.

| `TRANSACTIONAL` a|
- Concurrent updates are frequent
- Transactional access
| Indicates that concurrent writes are common, and the only way to maintain synchronization between the second-level cache and the database is via the use of a fully transactional cache provider. In this case, the cache and the database must cooperate via JTA or the XA protocol, and Hibernate itself takes on little responsibility for maintaining the integrity of the cache.
|===

Which policies make sense may also depend on the underlying second-level cache implementation.

[%unbreakable]
[NOTE]
// .The JPA-defined `@Cacheable` annotation
====
JPA has a similar annotation, named `@Cacheable`.
Unfortunately, it's almost useless to us, since:

- it provides no way to specify any information about the nature of the cached entity and how its cache should be managed, and
- it may not be used to annotate associations, and so we can't even use it to mark collection roles as eligible for storage in the second-level cache.
====

[[natural-id-cache]]
=== Caching by natural id

If our entity has a <<natural-id-attributes,natural id>>, we can enable an additional cache, which holds cross-references from natural id to primary id, by annotating the entity `@NaturalIdCache`.
By default, the natural id cache is stored in a dedicated region of the second-level cache, separate from the cached entity data.

[source,java]
----
@Entity
@Cache(usage=READ_WRITE, region="Book")
@NaturalIdCache(region="BookIsbn")
class Book {
    ...
    @NaturalId
    String isbn;

    @NaturalId
    int printing;
    ...
}
----

This cache is utilized when the entity is retrieved using one of the operations of `Session` which performs <<load-by-natural-id,lookup by natural id>>.

[NOTE]
====
Since the natural id cache doesn't contain the actual state of the entity, it doesn't make sense to annotate an entity `@NaturalIdCache` unless it's already eligible for storage in the second-level cache, that is, unless it's also annotated `@Cache`.
====

It's worth noticing that, unlike the primary identifier of an entity, a natural id might be mutable.

We must now consider a subtlety that often arises when we have to deal with so-called "reference data", that is, data which fits easily in memory, and doesn't change much.

[[caching-and-fetching]]
=== Caching and association fetching

Let's consider again our `Publisher` class:

[source,java]
----
@Cache(usage=NONSTRICT_READ_WRITE, region="Publishers")
@Entity
class Publisher { ... }
----

Data about publishers doesn't change very often, and there aren't so many of them.
Suppose we've set everything up so that the publishers are almost _always_ available in the second-level cache.

Then in this case we need to think carefully about associations of type `Publisher`.

[source,java]
----
@ManyToOne
Publisher publisher;
----

There's no need for this association to be lazily fetched, since we're expecting it to be available in memory, so we won't set it `fetch=LAZY`.
But on the other hand, if we leave it marked for eager fetching then, by default, Hibernate will often fetch it using a join.
This places completely unnecessary load on the database.

The solution is the link:{doc-javadoc-url}/org/hibernate/annotations/Fetch.html[`@Fetch`] annotation:

[source,java]
----
@ManyToOne @Fetch(SELECT)
Publisher publisher;
----

By annotating the association `@Fetch(SELECT)`, we suppress join fetching, giving Hibernate a chance to find the associated `Publisher` in the cache.

Therefore, we arrive at this rule of thumb:

[TIP]
====
Many-to-one associations to "reference data", or to any other data that will almost always be available in the cache, should be mapped `EAGER`,`SELECT`.

Other associations, as we've <<lazy-problem,already made clear>>, should be `LAZY`.
====

Once we've marked an entity or collection as eligible for storage in the second-level cache, we still need to set up an actual cache.

[[second-level-cache-configuration]]
=== Configuring the second-level cache provider

Configuring a second-level cache provider is a rather involved topic, and quite outside the scope of this document.
But in case it helps, we often test Hibernate with the following configuration, which uses EHCache as the cache implementation, as above in <<optional-dependencies>>:

:ehcache-config: https://www.ehcache.org/documentation/

.EHCache configuration
[%breakable,cols="35,~"]
|===
| Configuration property name              | Property value

| link:{doc-javadoc-url}org/hibernate/cfg/CacheSettings.html#CACHE_REGION_FACTORY[`hibernate.cache.region.factory_class`]   | `jcache`
| `hibernate.javax.cache.uri`              | `/ehcache.xml`
|===

If you're using EHCache, you'll also need to include an `ehcache.xml` file
that explicitly configures the behavior of each cache region belonging to
your entities and collections.
You'll find more information about configuring EHCache {ehcache-config}[here].

:caffeine: https://github.com/ben-manes/caffeine/

We may use any other implementation of JCache, such as {caffeine}[Caffeine].
JCache automatically selects whichever implementation it finds on the classpath.
If there are multiple implementations on the classpath, we must disambiguate using:

.Disambiguating the JCache implementation
[%breakable,cols="35,~"]
|===
| Configuration property name        | Property value

| `hibernate.javax.cache.provider`   a| The implementation of `javax.cache.spi.CachingProvider`, for example:
[%breakable,cols="~,20"]
!===
! `org.ehcache.jsr107.EhcacheCachingProvider` ! for EHCache
! `com.github.benmanes.caffeine.jcache.spi.CaffeineCachingProvider` ! for Caffeine
!===
|===

Alternatively, to use Infinispan as the cache implementation, the following settings are required:

:infinispan-hibernate: https://infinispan.org/docs/stable/titles/hibernate/hibernate.html

.Infinispan provider configuration
[%breakable,cols="35,~"]
|===
| Configuration property name              | Property value

| link:{doc-javadoc-url}org/hibernate/cfg/CacheSettings.html#CACHE_REGION_FACTORY[`hibernate.cache.region.factory_class`]   | `infinispan`
| `hibernate.cache.infinispan.cfg`         a| Path to infinispan configuration file, for example:
[%breakable,cols="~,35"]
!===
! `org/infinispan/hibernate/cache/commons/builder/infinispan-configs.xml`
! for a distributed cache
! `org/infinispan/hibernate/cache/commons/builder/infinispan-configs-local.xml`
! to test with local cache
!===
|===

Infinispan is usually used when distributed caching is required.
There's more about using Infinispan with Hibernate {infinispan-hibernate}[here].

Finally, there's a way to globally disable the second-level cache:

.Setting to disable caching
[%breakable,cols="35,~"]
|===
| Configuration property name              | Property value

| link:{doc-javadoc-url}org/hibernate/cfg/CacheSettings.html#USE_SECOND_LEVEL_CACHE[`hibernate.cache.use_second_level_cache`] | `true` to enable caching, or `false` to disable it
|===

When `hibernate.cache.region.factory_class` is set, this property defaults to `true`.

[%unbreakable]
[TIP]
====
This setting lets us easily disable the second-level cache completely when troubleshooting or profiling performance.
====

You can find much more information about the second-level cache in the {second-level-cache}[User Guide].

[[query-cache]]
=== Caching query result sets

The caches we've described above are only used to optimize lookups by id or by natural id.
Hibernate also has a way to cache the result sets of queries, though this is only rarely an efficient thing to do.

The query cache must be enabled explicitly:

.Setting to enable the query cache
[%breakable,cols="35,~"]
|===
| Configuration property name | Property value

| link:{doc-javadoc-url}org/hibernate/cfg/CacheSettings.html#USE_QUERY_CACHE[`hibernate.cache.use_query_cache`] | `true` to enable the query cache
|===

To cache the results of a query, use the link:{doc-javadoc-url}org/hibernate/query/QueryOption.ResultSetCache.html[`ResultSetCache`] option:

[source,java]
----
import org.hibernate.query.QueryOption.ResultSetCache;
...
entityManager.createQuery("from Product where discontinued = false")
             .ofType(Product.class)
             .addOption(new ResultSetCache(null))
             .getResultList();
----
//
// [source,java]
// ----
// entityManager.createQuery("from Product where discontinued = false")
//     .ofType(Product.class)
//     .unwrap(SelectionQuery.class)
//     .setCacheable(true)
//     .getResultList();
// ----

By default, the query result set is stored in a cache region named `default-query-results-region`.
Since different queries should have different caching policies, it's common to explicitly specify a region name:

[source,java]
----
entityManager.createQuery("from Product where discontinued = false")
             .ofType(Product.class)
             .addOption(new ResultSetCache("all-active-products"))
             .getResultList();
----

A result set is cached together with a _logical timestamp_.
By "logical", we mean that it doesn't actually increase linearly with time, and in particular it's not the system time.

When a `Product` is updated, Hibernate _does not_ go through the query cache and invalidate every cached result set that's affected by the change.
Instead, there's a special region of the cache which holds a logical timestamp of the most-recent update to each table.
This is called the _update timestamps cache_, and it's kept in the region `default-update-timestamps-region`.

[CAUTION]
====
It's _your responsibility_ to ensure that this cache region is configured with appropriate policies.
In particular, update timestamps should never expire or be evicted.
====

When a query result set is read from the cache, Hibernate compares its timestamp with the timestamp of each of the tables that affect the results of the query, and _only_ returns the result set if the result set isn't stale.
If the result set _is_ stale, Hibernate goes ahead and re-executes the query against the database and updates the cached result set.

As is generally the case with any second-level cache, the query cache can break the ACID properties of transactions.

[[second-level-cache-management]]
=== Second-level cache management

For the most part, the second-level cache is transparent.
Program logic which interacts with the Hibernate session is unaware of the cache, and is not impacted by changes to caching policies.

At worst, interaction with the cache may be controlled by specifying explicit cache modes:

// [source,java]
// ----
// session.setCacheMode(CacheMode.IGNORE);
// ----
//
// Or, using JPA-standard APIs:

[source,java]
----
entityManager.setCacheRetrieveMode(CacheRetrieveMode.BYPASS);
entityManager.setCacheStoreMode(CacheStoreMode.BYPASS);
----

The JPA-defined cache modes come in two flavors: `CacheRetrieveMode` and `CacheStoreMode`.

.JPA-defined cache retrieval modes
[%breakable,cols="30,~"]
|===
| Mode | Interpretation

| `CacheRetrieveMode.USE` | Read data from the cache if available
| `CacheRetrieveMode.BYPASS` | Don't read data from the cache; go direct to the database
|===

We might select `CacheRetrieveMode.BYPASS` if we're concerned about the possibility of reading stale data from the cache.

.JPA-defined cache storage modes
[%breakable,cols="30,~"]
|===
| Mode | Interpretation

| `CacheStoreMode.USE` | Write data to the cache when read from the database or when modified; do not update already-cached items when reading
| `CacheStoreMode.REFRESH` | Write data to the cache when read from the database or when modified; always update cached items when reading
| `CacheStoreMode.BYPASS` | Don't write data to the cache
|===

We should select `CacheStoreMode.BYPASS` if we're querying data that doesn't need to be cached.

[%unbreakable]
[TIP]
// .A good time to `BYPASS` the cache
====
It's a good idea to set the `CacheStoreMode` to `BYPASS` just before running a query which returns a large result set full of data that we don't expect to need again soon.
This saves work, and prevents the newly-read data from pushing out the previously cached data.

[source,java]
----
List<Publisher> allpubs =
        entityManager.createQuery("from Publisher", Publisher.class)
            .setCacheStoreMode(CacheStoreMode.BYPASS)
            .getResultList();
----
====

A Hibernate link:{doc-javadoc-url}/org/hibernate/CacheMode.html[`CacheMode`] packages a `CacheRetrieveMode` with a `CacheStoreMode`.

.Hibernate cache modes and JPA equivalents
[%breakable,cols="30,~"]
|===
| Hibernate `CacheMode` | Equivalent JPA modes

| `NORMAL` | `CacheRetrieveMode.USE`, `CacheStoreMode.USE`
| `IGNORE` | `CacheRetrieveMode.BYPASS`, `CacheStoreMode.BYPASS`
| `GET` | `CacheRetrieveMode.USE`, `CacheStoreMode.BYPASS`
| `PUT` | `CacheRetrieveMode.BYPASS`, `CacheStoreMode.USE`
| `REFRESH` | `CacheRetrieveMode.BYPASS`, `CacheStoreMode.REFRESH`
| `REFRESH_SESSION` | none
|===

The `REFRESH_SESSION` mode specifies that entity state returned by a query should overwrite state held in the persistence context, just as if `refresh()` had been called.

[source,java]
----
List<Publisher> refreshed =
        entityManager.createQuery("from Publisher", Publisher.class)
            .addOption(CacheMode.REFRESH_SESSION)
            .getResultList();
----

Apart from `REFRESH_SESSION`, there's no particular reason to prefer Hibernate's `CacheMode` over the JPA equivalents.
This enumeration only exists because Hibernate had cache modes long before they were added to JPA.

[%unbreakable]
[TIP]
====
For "reference" data, that is, for data which is expected to always be found in the second-level cache, it's a good idea to _prime_ the cache at startup.
There's a really easy way to do this: just execute a query immediately after obtaining the
`EntityManager` or `SessionFactory`.

[source,java]
----
SessionFactory sessionFactory =
        setupHibernate(new Configuration())
            .buildSessionFactory();
// prime the second-level cache
sessionFactory.inSession(session -> {
    session.createQuery("from Country")
        .ofType(Country.class)
        .setReadOnly(true)
        .getResultList();
    session.createQuery("from Product where discontinued = false")
        .ofType(Product.class)
        .setReadOnly(true)
        .getResultList();
});

----
====

Very occasionally, it's necessary or advantageous to control the cache explicitly.
For example, we might need to evict some data that we know to be stale because it was updated:

- via direct JDBC, or
- by some other program.

The JPA-standard `Cache` interface allows programmatic eviction of cached entities.

[source,java]
----
entityManagerFactory.getCache()
        .evict(Book.class, bookId);
----

Unfortunately, as we've already observed above, JPA provides a quite poor approximation to Hibernate's very granular and flexible second-level cache architecture.
The link:{doc-javadoc-url}org/hibernate/Cache.html[`Cache`] interface allows much more control over programmatic eviction of cached items.

[source,java]
----
entityManagerFactory.getCache()
        .unwrap(Cache.class)
        .evictEntityData(Book.class, bookId);
----

[%unbreakable]
[CAUTION]
// .Second-level cache management is not transaction-aware
====
Second-level cache management via the `Cache` interface is not transaction-aware.
None of the operations of `Cache` respect any isolation or transactional semantics associated with the underlying caches. In particular, eviction via the methods of this interface causes an immediate "hard" removal outside any current transaction and/or locking scheme.
====

Ordinarily, however, Hibernate automatically evicts or updates cached data after modifications, and, in addition, cached data which is unused will eventually be expired according to the configured policies.

This is quite different to what happens with the first-level cache.

[[session-cache-management]]
=== Session cache management

Entity instances aren't automatically evicted from the session cache when they're no longer needed.
Instead, they stay pinned in memory until the session they belong to is discarded by your program.
So if you query many entities from within a single persistence context, you might experience very poor performance.
In such cases, it becomes necessary to manage the session cache manually.

The methods `detach()` and `clear()` allow you to remove entities from the session cache, making them available for garbage collection.
Since most sessions are rather short-lived, you won't need these operations very often.
And if you find yourself thinking you _do_ need them in a certain situation, you should strongly consider an alternative solution: a _stateless session_.

[TIP]
====
The very best way to avoid having too many entities pinned in the session cache is to not load them from the database in the first place.
Many operations can be performed more efficiently on the database server.
This is especially true for bulk operations.

To update many entities at once, use an `update` statement:

[source, hql]
----
entityAgent.createStatement(
        """
        update Book as b
            set b.totalSales =
                coalesce((select sum(quantity) from OrderItem where book = b), 0)
        """
        ).execute();
----

To insert many entities at once, use `insert ... select`:

[source, hql]
----
entityAgent.createStatement(
        """
        insert into OrderQueue (id, isbn, quantity, customerId)
            select o.id, i.book.isbn, i.quantity, o.customer.id
            from Order o join o.items i
            where o.status = PENDING
        """
        ).execute();
----

For more complicated operations, consider using a stored procedure.
====

[[stateless-sessions]]
=== Stateless sessions

An arguably underappreciated feature of Hibernate is the ability to program with <<bypass-persistence-context,stateless sessions>>, which provide a command-oriented, more bare-metal approach to interacting with the database.
This capability has only recently been formalized in the JPA specification via the addition of the `EntityAgent` interface.

A stateless session:

- doesn't have a first-level cache (persistence context), and
- doesn't implement transactional write-behind or automatic dirty checking, so all operations are executed immediately when they're explicitly called.

There are some advantages to this model.
In particular, the absence of a persistence context means that we can safely perform bulk-processing tasks without allocating huge quantities of memory.
Use of a stateless session alleviates the need to call `clear()` or `detach()` to perform first-level cache management.

[%unbreakable]
[TIP]
====
Stateless sessions can be useful, but for bulk operations on huge datasets, Hibernate can't possibly compete with stored procedures!
====


[[optimistic-and-pessimistic-locking]]
=== Optimistic and pessimistic locking

Finally, an aspect of behavior under load that we didn't mention above is row-level data contention.
When many transactions try to read and update the same data, the program might become unresponsive with lock escalation, deadlocks, and lock acquisition timeout errors.

There's two basic approaches to data concurrency in Hibernate:

- optimistic locking using <<version-attributes,`@Version` columns>>, and
- database-level pessimistic locking using the SQL `for update` syntax (or equivalent).

In the Hibernate community it's _much_ more common to use optimistic locking, and Hibernate makes that incredibly easy.

[%unbreakable]
[TIP]
====
Where possible, in a multiuser system, avoid holding a pessimistic lock across a user interaction.
Indeed, the usual practice is to avoid having transactions that span user interactions. For multiuser systems, optimistic locking is king.
====

That said, there _is_ also a place for pessimistic locks, which can sometimes reduce the probability of transaction rollbacks.

Therefore, the `get()`, `find()`, `lock()`, and `refresh()` methods accept a link:{doc-javadoc-url}/org/hibernate/LockMode.html[`LockMode`] as an option.
Here's the simplest way to execute a `select ... for update` in Hibernate:

[source,java]
Book book = session.get(Book.class, isbn, LockMode.PESSIMISTIC_WRITE);

We can also link:{doc-javadoc-url}/org/hibernate/query/SelectionQuery.html#setLockMode(jakarta.persistence.LockModeType)[specify] a `LockMode` for a query.

A lock mode can be used to request a pessimistic lock, or to customize the behavior of optimistic locking:

.Optimistic and pessimistic lock modes
[%breakable,cols="26,~"]
|===
| `LockMode` type | Meaning

| `READ`                        | An optimistic lock obtained implicitly whenever
an entity is read from the database using `select`
| `OPTIMISTIC`                  | An optimistic lock obtained when an entity is
read from the database, and verified using a
`select` to check the version when the
transaction completes
| `OPTIMISTIC_FORCE_INCREMENT`  | An optimistic lock obtained when an entity is
read from the database, and enforced using an
`update` to increment the version when the
transaction completes
| `WRITE`                       | A pessimistic lock obtained implicitly whenever
an entity is written to the database using
`update` or `insert`
| `PESSIMISTIC_READ`            | A pessimistic `for share` lock
| `PESSIMISTIC_WRITE`           | A pessimistic `for update` lock
| `PESSIMISTIC_FORCE_INCREMENT` | A pessimistic lock enforced using an immediate
`update` to increment the version
| `NONE`                        | No lock; assigned when an entity is read from the second-level cache
|===

Note that an `OPTIMISTIC` lock is always verified at the end of the transaction, even when the entity has not been modified.
This is slightly different to what most people mean when they talk about an "optimistic lock".
It's never necessary to request an `OPTIMISTIC` lock on a modified entity, since the version number is always verified when a SQL `update` is executed.

[CAUTION]
====
JPA has its own `LockModeType`, which enumerates most of the same modes.
However, JPA's `LockModeType.READ` is a synonym for `OPTIMISTIC` -- it's not the same as Hibernate's `LockMode.READ`.
Similarly, `LockModeType.WRITE` is a synonym for `OPTIMISTIC_FORCE_INCREMENT` and is not the same as `LockMode.WRITE`.
====

A pessimistic lock request may be combined with an explicit `Timeout`.

[source,java]
session.lock(book, LockMode.PESSIMISTIC_WRITE, Timeout.seconds(2))

The interface link:{doc-javadoc-url}/org/hibernate/Timeouts.html[`Timeouts`] defines some special instances of `Timeout` which may be used to request use of link:{doc-javadoc-url}/org/hibernate/Timeouts.html#NO_WAIT[`for update nowait`] or link:{doc-javadoc-url}/org/hibernate/Timeouts.html#SKIP_LOCKED[`for update skip locked`] on databases which support these options.

[source,java]
session.lock(book, LockMode.PESSIMISTIC_WRITE, Timeouts.NO_WAIT)


[[statistics]]
=== Collecting statistics

We may ask Hibernate to collect statistics about its activity by setting this configuration property:

[%breakable,cols="35,~"]
|===
| Configuration property name | Property value

| link:{doc-javadoc-url}org/hibernate/cfg/StatisticsSettings.html#GENERATE_STATISTICS[`hibernate.generate_statistics`] | `true` to enable collection of statistics
|===

The statistics are exposed by the link:{doc-javadoc-url}org/hibernate/stat/Statistics.html[`Statistics`] object exposed by `SessionFactory`:

[source,java]
----
var sessionFactory =
        entityManagerfactory.unwrap(SessionFactory.class);

long failedVersionChecks =
        sessionFactory.getStatistics()
            .getOptimisticFailureCount();

long publisherCacheMissCount =
        sessionFactory.getStatistics()
            .getEntityStatistics(Publisher.class.getName())
                .getCacheMissCount();
----

:micrometer: https://quarkus.io/guides/micrometer
:smallrye-metrics: https://quarkus.io/guides/microprofile-metrics

Hibernate's statistics enable observability.
Both {micrometer}[Micrometer] and {smallrye-metrics}[SmallRye Metrics] are capable of exposing these metrics.

[NOTE]
====
To use the Micrometer integration, the application must include `org.hibernate.orm:hibernate-micrometer` on the classpath,
as well as an appropriate version of `io.micrometer:micrometer-core`.
This version of Hibernate ORM is compatible with Micrometer {micrometerVersion}.
====

[[jfr]]
=== Using Java Flight Recorder

Hibernate JFR is a separate module that reports events to link:https://developers.redhat.com/blog/2020/08/25/get-started-with-jdk-flight-recorder-in-openjdk-8u[Java Flight Recorder].
This is different to reporting aggregated <<statistics,metrics>> via a tool like Micrometer, since JFR records information about the timing and duration of each discrete event, along with a stack trace.
If anything, the information reported by JFR is a little _too_ detailed to make it really useful for performance tuning--it's perhaps more useful for _troubleshooting_.

No special configuration is required to use Hibernate JFR.
Just include `org.hibernate.orm:hibernate-jfr` as a runtime dependency.
In particular, you _don't_ need to enable `hibernate.generate_statistics`.

[[slow-queries]]
=== Tracking down slow queries

When a poorly-performing SQL query is discovered in production, it can sometimes be hard to track down exactly where in the Java code the query originates.
Hibernate offers two configuration properties that can make it easier to identify a slow query and find its source.

.Settings for tracking slow queries
[%breakable,cols="25,~,~"]
|===
| Configuration property name | Purpose | Property value

| link:{doc-javadoc-url}org/hibernate/cfg/JdbcSettings.html#LOG_SLOW_QUERY[`hibernate.log_slow_query`] | Log slow queries at the `INFO` level | The minimum execution time, in milliseconds, which characterizes a "slow" query
| link:{doc-javadoc-url}org/hibernate/cfg/JdbcSettings.html#USE_SQL_COMMENTS[`hibernate.use_sql_comments`] | Prepend comments to the executed SQL | `true` or `false`
|===

When `hibernate.use_sql_comments` is enabled, the text of the HQL query is prepended as a comment to the generated SQL, which usually makes it easy to find the HQL in the Java code.

The comment text may be customized:

- using the link:{doc-javadoc-url}/org/hibernate/query/QueryOption.Comment.html[`Comment`] option, or
- via the `@NamedQuery` annotation.

[TIP]
====
Once you've identified a slow query, one of the best ways to make it faster is to _actually go and talk to someone who is an expert at making queries go fast_.
These people are called "database administrators", and if you're reading this document you probably aren't one.
Database administrators know lots of stuff that Java developers don't.
So if you're lucky enough to have a DBA about, you don't need to Dunning-Kruger your way out of a slow query.
====

An expertly-defined index might be all you need to fix a slow query.

[[indexes]]
=== Adding indexes

The `@Index` annotation may be used to add an index to a table:

[source,java]
----
@Entity
@Table(indexes=@Index(columnList="title, year, publisher_id"))
class Book { ... }
----

It's even possible to specify an ordering for an indexed column, or that the index should be case-insensitive:

[source,java]
----
@Entity
@Table(indexes=@Index(columnList="(lower(title)), year desc, publisher_id"))
class Book { ... }
----

This lets us create a customized index for a particular query.

Note that SQL expressions like `lower(title)` must be enclosed in parentheses in the `columnList` of the index definition.

[TIP]
====
It's not clear that information about indexes belongs in annotations of Java code.
Indexes are usually maintained and modified by a database administrator, ideally by an expert in tuning the performance of one particular RDBMS.
So it might be better to keep the definition of indexes in a SQL DDL script that your DBA can easily read and modify.
<<automatic-schema-export,Remember>>, we can ask Hibernate to execute a DDL script using the property `javax.persistence.schema-generation.create-script-source`.
====

[[denomalized-date]]
=== Dealing with denormalized data

A typical relational database table in a well-normalized schema has a relatively small number of columns, and so there's little to be gained by selectively querying columns and populating only certain fields of an entity class.

But occasionally, we hear from someone asking how to map a table with a hundred columns or more!
This situation can arise when:

- data is intentionally denormalized for performance,
- the results of a complicated analytic query are exposed via a view, or
- someone has done something crazy and wrong.

Let's suppose that we're _not_ dealing with the last possibility.
Then we would like to be able to query the monster table without returning all of its columns.
At first glance, Hibernate doesn't offer a perfect bottled solution to this problem.
This first impression is misleading.
Actually, Hibernate features more than one way to deal with this situation, and the real problem is deciding between the ways.
We could:

1. map multiple entity classes to the same table or view, being careful about "overlaps" where a mutable column is mapped to more than one of the entities,
2. use <<hql-queries,HQL>> or <<native-queries,native SQL>> queries returning <<projection-lists,results into record types>> instead of retrieving entity instances, or
3. use the <<bytecode-enhancer,bytecode enhancer>> and link:{doc-javadoc-url}org/hibernate/annotations/LazyGroup.html[`@LazyGroup`] for attribute-level lazy fetching.

Some other ORM solutions push the third option as the recommended way to handle huge tables, but this has never been the preference of the Hibernate team or Hibernate community.
It's much more typesafe to use one of the first two options.

[[hibernate-reactive]]
=== Reactive programming with Hibernate

:hr: https://hibernate.org/reactive/
:hr-guide: https://hibernate.org/reactive/documentation/3.0/reference/html_single/

Finally, many systems which require high scalability now make use of reactive programming and reactive streams.
{hr}[Hibernate Reactive] brings O/R mapping to the world of reactive programming.
You can learn much more about Hibernate Reactive from its {hr-guide}[Reference Documentation].

[TIP]
====
Hibernate Reactive may be used alongside vanilla Hibernate in the same program, and can reuse the same entity classes.
This means you can use the reactive programming model exactly where you need it—perhaps only in one or two places in your system.
You don't need to rewrite your whole program using reactive streams.
====

---

--- METRICS ---
- Files Extracted: 29
- Estimated Token Budget: ~134552 tokens
- Canonical Reference: https://codewiki.google/github.com/hibernate/hibernate-orm
