Card 05/ 07
Transaction Propagation: REQUIRES_NEW vs REQUIRED
An audit entry that survives the rollback of the operation it records.
Propagation decides what a @Transactional method does when it is called while another transaction is already open. The default, REQUIRED, joins the existing transaction, so both share one outcome. REQUIRES_NEW pauses the caller's transaction and starts an independent one that commits or rolls back on its own.
Both are set the same way, through the propagation attribute of @Transactional, and both behave identically when no transaction is open: each starts one. Spring has other values, such as MANDATORY and SUPPORTS, which are rarely needed.
bookRideThenFail() writes an audit entry through logIndependently() and then throws. Because logIndependently is REQUIRES_NEW, and lives in a separate bean so the call goes through its proxy (the wrapper Spring uses to start transactions), its write survives the caller's rollback:
@Transactional(propagation = Propagation.REQUIRES_NEW)
void logIndependently(String note) {
repo.save(new AuditEntity(note));
}
@Transactional
void bookRideThenFail() {
auditService.logIndependently("attempted booking");
throw new RuntimeException("booking failed after logging");
}REQUIRES_NEW audit log survived caller's rollback: count = 1| Propagation | When called inside an existing transaction |
|---|---|
REQUIRED (the default) | Joins it: one transaction, one outcome for both methods |
REQUIRES_NEW | Pauses the caller's transaction and runs its own, which commits or rolls back independently |
The decision rule. Use REQUIRES_NEW for work that must be recorded whether or not the operation around it succeeds, such as an audit entry or a record of a failed attempt. Use the default, REQUIRED, whenever the two pieces of work should succeed or fail together, which is most of the time.
← → move through sections and cards