# 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 |