Add multi-datasource module: two databases with per-database DataSource, Flyway, EntityManagerFactory and transaction manager on Boot 4.1

Working setup plus one small application per way of getting it wrong (no @Primary, @Primary only, url vs jdbc-url, wrong repository package, Flyway auto-configuration), plain vs named @Transactional, and ChainedTransactionManager with a failing commit. Transcripts are written by the tests.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Uu7q8vPeREyT4218EJPzz1
This commit is contained in:
Claude
2026-09-24 09:38:27 +00:00
parent d6b76c57db
commit e59ff029a1
44 changed files with 1465 additions and 0 deletions
+67
View File
@@ -0,0 +1,67 @@
# multi-datasource
Companion project for the article **[Multiple DataSources in Spring Boot 4 with Spring Data JPA](https://ankurm.com/multiple-datasources-spring-boot-4-spring-data-jpa/)** on **[ankurm.com](https://ankurm.com)**.
Two H2 databases (`customers` and `orders`), each with its own `DataSource`, Flyway, `EntityManagerFactory`,
transaction manager and repository scan; plus one small application per way of getting that wrong.
Every console block quoted in the article came out of `output/`. Transcripts 01-09 are written by the test
suite (so a claim that stops being true turns the build red); 10-12 are read out of jars and `javac` by
`scripts/capture-facts.sh`.
There is deliberately **no `docs/` folder**: the deeper material lives in collapsible "going deeper"
sections inside the article itself, next to the paragraph each one extends.
## Versions
| | |
|---|---|
| Spring Boot | 4.1.1 |
| Spring Framework | 7.0.9 |
| Spring Data JPA / Commons | 4.1.1 |
| Hibernate ORM | 7.4.5.Final |
| Flyway | 12.4.0 |
| JDK | 25 (Temurin 25.0.4.1+1) |
| Maven | 3.9 |
| H2 | 2.4.240 (the version Boot 4.1.1 manages) |
## Quickstart
```bash
export JAVA_HOME=/path/to/jdk-25
mvn test # runs every scenario and rewrites output/01-09
./scripts/run-all.sh # everything, including 10-12
```
## Source layout
| Path | What it holds |
|---|---|
| `customers/` | `Customer`, `CustomerRepository` and `CustomersDbConfig`: the `@Primary` database |
| `orders/` | `PurchaseOrder`, `OrderRepository` and `OrdersDbConfig`: the second database |
| `service/PlacementService` | writes to both databases, then optionally throws; plain and named `@Transactional` |
| `MultiDsApp` | scans only the three packages above |
| `traps/nodefault` | two `DataSource` beans, none `@Primary` |
| `traps/primaryonly` | one `@Primary` `DataSource`, Boot's own JPA setup: it starts and uses the wrong database |
| `traps/jdbcurl` | `@ConfigurationProperties` bound straight onto a pool with a `url` key |
| `traps/builderdefaults` | what a hand-built `EntityManagerFactory` still gets from Spring Boot |
| `traps/flywayauto` | Spring Boot's Flyway auto-configuration with two databases |
| `traps/wrongpackage` | a repository whose entity is not in the factory it is scanned against |
| `src/test/.../chain/` | `ChainedTransactionManager`, and a transaction manager whose commit fails |
| `src/main/resources/db/migration/{customers,orders}/` | one Flyway location per database |
## Index of captured output
| File | Written by | What it shows |
|---|---|---|
| `01-two-databases.txt` | `TwoDatabasesTests` | pools, Flyway histories, what each factory manages, where each repository writes |
| `02-no-primary.txt` | `TrapsTests` | two `DataSource` beans without `@Primary` |
| `03-primary-only-wrong-database.txt` | `TrapsTests` | it starts, and both tables are in the customers database |
| `04-url-vs-jdbc-url.txt` | `TrapsTests` | `url` does not bind onto a pool |
| `05-builder-defaults.txt` | `TrapsTests` | naming strategy and `ddl-auto` on a hand-built factory |
| `06-flyway-auto-configuration.txt` | `TrapsTests` | three ways Flyway auto-configuration meets two databases, and which database each one migrated |
| `07-wrong-package.txt` | `TrapsTests` | `Not a managed type` |
| `08-which-transaction-manager.txt` | `TwoDatabasesTests` | plain vs named `@Transactional` |
| `09-chained-transaction-manager.txt` | `ChainedTests` | rollback, and commit failure in both list orders |
| `10-chained-transaction-manager-jar.txt` | `capture-facts.sh` | `ChainedTransactionManager` is still shipped, and `@Deprecated` |
| `11-enable-jpa-repositories-not-repeatable.txt` | `capture-facts.sh` | `javac` on two `@EnableJpaRepositories` on one class |
| `12-builder-packages.txt` | `capture-facts.sh` | `Builder.packages(Class...)` derives a package name from each class |