Transactions in spring boot testing not rolled back
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Spring Boot tests often rely on transactional rollback to keep the database clean between runs. When rollback does not happen, test isolation breaks and failures become flaky. The issue usually comes from transaction boundaries, wrong test annotations, or code paths that commit outside the test transaction.
How Test Rollback Works
In Spring tests, rollback occurs when the test method runs inside a managed transaction and completes. The common pattern is using @Transactional on the test class or method.
If writes happen in another transaction scope, rollback may not apply.
Common Causes of Missing Rollback
Typical root causes include:
- Using
@Commitor explicit transaction commit in test. - Running code in separate thread where test transaction context is absent.
- Service methods annotated with
REQUIRES_NEWcreating independent commits. - Using non-transactional test slices with manual data setup.
Check service propagation settings first when behavior is surprising.
Independent transactions are valid in production but may leave rows after tests.
Keep Tests Deterministic
A pragmatic strategy is to avoid REQUIRES_NEW paths in most integration tests unless they are the explicit subject of the test. For those cases, add cleanup steps or use test containers reset.
Manual cleanup is slower but reliable for edge transaction cases.
Verify Transaction Context in Tests
You can assert active transaction state during test execution.
This quick check confirms whether rollback can even be expected.
Configuration Checks
Ensure test points to the intended database and profile. Rollback confusion sometimes comes from writing to a different datasource than the one you inspect.
Consistent test configuration reduces hidden state leakage.
Async and Event-Driven Side Effects
Rollback does not automatically undo effects triggered through async executors, messaging systems, or external APIs. If test code publishes events that process in separate transactions, database state can persist.
For deterministic tests, disable async behavior or replace with synchronous test doubles.
Transactional Test Utilities
Use TestTransaction when you need explicit control over transaction boundaries in tests.
This helps debug where commits happen and why rollback did not occur.
Test Slice Differences
Different Spring test slices provide different transaction semantics. For example, data-layer slices often default to rollback behavior, while full integration tests depend on explicit annotations.
Knowing slice behavior avoids false assumptions about automatic cleanup.
Practical Stabilization Checklist
A practical checklist for flaky rollback tests:
- Confirm active transaction in test thread.
- Inspect propagation settings on called services.
- Disable async paths in test profile.
- Add explicit cleanup for non-transactional side effects.
This approach stabilizes suites without guessing.
Common Pitfalls
- Assuming rollback applies across threads or async executors.
- Ignoring
REQUIRES_NEWtransactional boundaries in service methods. - Combining
@Transactionaltests with explicit commit annotations. - Inspecting a different database than the one used by tests.
- Relying on rollback for tests that intentionally commit side effects.
Summary
- Rollback works only inside the managed test transaction scope.
- Independent transaction propagation can bypass test rollback.
- Verify transaction activity during tests when debugging.
- Use cleanup hooks for scenarios that must commit independently.
- Keep datasource and profile configuration explicit and test-specific.
Related reading
- Transactions with DynamoDB library Boto3
- TransactionScope automatically escalating to MSDTC on some machines?
- Transpose rows to columns in clickhouse
- Trouble connecting to postgres from outside Kubernetes cluster
- TreeMap sort by value
- Trigger 404 in Spring-MVC controller?
- Trying to mock datetime.date.today, but not working
- UI Testing Failure - Neither element nor any descendant has keyboard focus on secureTextField

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.