Card 02/ 07

ExampleDifficulty: Intermediate1 min

Transactions Example: Two Writes Committed Together

Two saves in one method land in the database together, or not at all.

Inside one @Transactional method, several writes form a single unit: they are committed together when the method returns. bookTrip makes two separate save() calls, and the ordinary, working case looks like this:

java
@Transactional
void bookTrip() {
    repo.save(new TripEntity("booked"));
    repo.save(new TripEntity("booked"));
}
text
both rows committed together, count = 2
run in a container: neither save is visible until the method returns successfully

Neither save() call commits anything on its own. Each one adds a change to the transaction the method opened, and that transaction commits once, after both writes have succeeded, which is why the count jumps from 0 to 2 in one step.

Another connection querying the table while the method runs would see neither row, because at the default isolation level of most databases (the setting that decides what one transaction can see of another's work) uncommitted changes are invisible to other transactions.

Had the second save failed with an unchecked exception (a RuntimeException or one of its subclasses), the first would have been rolled back, meaning undone, with it, and the count would have stayed at 0.

So everything a @Transactional method writes shares one outcome. Two things quietly break that guarantee: a checked exception, which does not roll back by default, and a call to the method from inside its own class, which bypasses the transaction entirely.