Got a Spring service? You write a @Transactional method. Inside it, you call another private or protected method also annotated @Transactional. You expect separate transaction behavior or isolation. Here's the kicker: it often won't happen.
Spring's @Transactional magic relies on AOP proxies. When you call a method on a proxied bean from outside, the proxy intercepts it applying the transaction logic. But an internal call, like this.myPrivateTransactionalMethod(), bypasses the proxy entirely. This means the inner method's @Transactional annotation is simply ignored. It runs within the caller's transaction context or with no transaction at all if the caller wasn't transactional.
Consider this:
@Service
public class OrderService {
@Transactional
public void placeOrder(Order order) {
// save order
this.updateInventory(order.getItems()); // internal call
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void updateInventory(List<Item> items) {
// update inventory counts
}
}
Here, updateInventory will not get its own REQUIRES_NEW transaction. It's bound to placeOrder's transaction. If updateInventory fails, both operations roll back. The REQUIRES_NEW is effectively moot.
To correctly isolate transactions for such logic, extract it into a separate, Spring-managed component and inject it. Call the method on the injected component. Understand Spring's proxy mechanics; they're key.
Top comments (0)