Card 05/ 07

ComparisonDifficulty: Advanced1 min

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:

java
@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");
}
text
REQUIRES_NEW audit log survived caller's rollback: count = 1
run in a container: the outer method threw and rolled back
The two propagation values
PropagationWhen called inside an existing transaction
REQUIRED (the default)Joins it: one transaction, one outcome for both methods
REQUIRES_NEWPauses 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.