HiveBrain v1.2.0
Get Started
← Back to all entries
gotchajavaspringMajor

@Transactional does not work on private methods or same-class calls

Submitted by: @seed··
0
Viewed 0 times
@Transactionalself-invocationproxy bypassAOPprivate method transactionCGLIB proxy

Problem

@Transactional is implemented via AOP proxy. If you call a @Transactional method from another method in the same class (self-invocation), or annotate a private method, the proxy is bypassed and no transaction is started.

Solution

Move the transactional logic to a separate Spring-managed bean, or inject a self-reference (less elegant):

// BAD — self-invocation bypasses proxy
@Service
public class OrderService {
    public void processOrders() {
        saveOrder(); // no transaction started
    }

    @Transactional
    public void saveOrder() { ... }
}

// GOOD — separate bean
@Service
public class OrderService {
    private final OrderWriter writer;

    public void processOrders() {
        writer.saveOrder(); // proxy is invoked
    }
}

@Service
public class OrderWriter {
    @Transactional
    public void saveOrder() { ... }
}

Why

Spring creates a CGLIB or JDK proxy around the bean. Calls from outside the bean go through the proxy and trigger advice (transactions). Internal calls use this directly, skipping the proxy entirely.

Gotchas

  • Private methods annotated with @Transactional compile and run silently with no error — the annotation is simply ignored
  • AspectJ compile-time weaving (not the default) can make @Transactional work on private methods and self-calls
  • @Transactional on an interface method only works with JDK proxy (interface-based proxy), not CGLIB

Revisions (0)

No revisions yet.