This project demonstrates how to perform distributed transactions across multiple databases at runtime using Spring Boot, JTA, Atomikos, and a custom AbstractRoutingDataSource.
A User belongs to a Branch, and each branch has its own separate database. When a withdrawal request is made:
- The app deletes the user from the main database.
- It looks up the DB credentials of the user’s branch from the
branch_infotable. - It dynamically registers and switches to the appropriate branch database.
- It deletes the user’s wallet data (
point_wallet) from the branch DB. - All operations happen within a single distributed transaction.
- If any step fails, everything is rolled back.
com.example.multitransaction
├── main # Main DB (User, BranchInfo)
│ └── service # UserService, BranchInfoService
├── branch # Branch DB (PointWallet)
│ └── service # PointWalletService
├── core # Withdrawal orchestration
│ └── service # UserWithdrawalService
├── config
│ └── db # Atomikos config, routing, JTA
│ ├── DatabaseContextHolder.java
│ ├── DynamicRoutingDataSource.java
│ ├── RoutingDataSourceConfig.java
│ ├── MainDbConfig.java
│ ├── BranchDbConfig.java
│ ├── BranchDatabaseService.java
│ └── JtaConfig.java
└── MultiTransactionApplication.java # Main application class
- Spring Boot 3+
- Spring Data JPA (Hibernate)
- Atomikos JTA Transaction Manager
- MySQL 8
- Docker & Docker Compose
Make sure you're using JDK 17+.
./gradlew clean build -x testThis creates the JAR at:
build/libs/multi-transaction-0.0.1-SNAPSHOT.jar
docker compose upThis will spin up the following containers:
| Container | Description | Port |
|---|---|---|
main-db |
Main database | 13305 |
tesco-db |
Branch DB (Tesco) | 13306 |
lidl-db |
Branch DB (Lidl) | 13307 |
multi-transaction |
Spring Boot API | 8080 |
Each database is initialized using SQL files from the /init directory:
init/
├── main/
│ └── init.sql # user, branch_info
├── tesco/
│ └── init.sql # point_wallet
└── lidl/
└── init.sql # point_wallet
- ✅ Dynamically switch to multiple databases at runtime
- ✅ Perform global transactions across databases using
@Transactional - ✅ Maintain data consistency across systems using Atomikos and XA
- ✅ Easy to extend for multi-tenant or branch-based SaaS systems