AOP proxiessenior8+ years

A method is annotated with both `@Transactional` and `@Cacheable`. A call that fails partway through, after the value was already computed and cached, rolls back its database writes — but the next call still returns the cached (now-inconsistent) value instead of recomputing it. What determines which annotation's advice actually wraps which, and how would you fix the ordering?

When two proxy-based annotations sit on the same method, they become two nested layers of advice, and which one is the outer layer and which is the inner one determines the order operations actually happen in — and that order is controlled by @Order on the underlying aspects (or, by default, Spring's own internal ordering for its own annotations), not by the order the annotations happen to be written in the source. If @Transactional ends up as the outer layer, wrapping @Cacheable inside it, then a cache write happens inside the transaction — and a later rollback of that transaction has no effect on the cache at all, since the cache isn't a transactional resource, so the just-computed, about-to-be-discarded value stays cached and gets served to the next caller. The fix is to make @Transactional the inner layer relative to caching, so the transaction (and any rollback) completes fully before the cache is ever written to.

The lesson behind it →
More on AOP proxies