SoFunction
Updated on 2025-04-27

Spring @Transactional Self-call problem in-depth analysis and solution

Spring @Transactional Deep Analysis of Self-Calling Problems

The nature of the problem: Self-call transaction fails

When method A inside class calls another class with@TransactionalWhen the method B of the annotation is explained, the transaction annotation will not take effect. This is because Spring's transaction management is implemented based on AOP proxy, and self-calling will bypass the proxy mechanism.

Principle analysis

1. Spring transaction implementation mechanism

Spring transactions are implemented through dynamic proxying, and there are two ways:

  • JDK dynamic proxy: Based on interface
  • CGLIB Agent: Based on class inheritance
// Original call process (expected transaction process)caller → Proxy object → Target object.methodB()
// The actual process during self-callcaller → Target object.methodA() → Target object.methodB() [Bypass the proxy]

2. Self-call problem example

@Service
public class OrderService {
    public void placeOrder(Order order) {
        // Self-call causes transaction failure        validateOrder(order);
        // Other business logic...    }
    @Transactional
    public void validateOrder(Order order) {
        // Database verification operation...    }
}

Solution

Solution 1: Inject your own agent (recommended)

@Service
public class OrderService {
    @Autowired
    private OrderService selfProxy; // Inject proxy object    public void placeOrder(Order order) {
        (order); // Call via proxy    }
    @Transactional
    public void validateOrder(Order order) {
        // The transaction takes effect    }
}

Solution 2: Refactoring the code structure

@Service
@RequiredArgsConstructor
public class OrderService {
    private final OrderValidator orderValidator;
    public void placeOrder(Order order) {
        (order);
    }
}
@Service
class OrderValidator {
    @Transactional
    public void validate(Order order) {
        // Transaction operation    }
}

Solution 3: Use AspectJ mode (weaving at compile time)

# 
-target-class=true
=false

Technical depth: Spring transaction proxy mechanism

Agent creation process

  • Create original beans when container starts
  • passAbstractAutoProxyCreatorCreate a proxy
  • right@TransactionalMethods to add interceptors

Transaction interceptor call stack

()
→ ()
→ ()
→ Final call to the target method

Production environment best practices

Unify transaction boundaries

@Service
@Transactional // Class level annotationpublic class OrderService {
    public void placeOrder() {
        // All public methods have transactions by default    }
}

Transaction monitoring

@Aspect
@Component
public class TransactionMonitor {
    @Around("@annotation(transactional)")
    public Object monitor(ProceedingJoinPoint pjp, Transactional transactional) 
        throws Throwable {
        // Record transaction start/end    }
}

Exception handling

@Transactional(rollbackFor = {, })
public void process() {
    // Identify the rollback exception type}

Common Mistakes

Private method annotation

@Transactional // Invalid!private void internalMethod() {}

Final method annotation

@Transactional // Invalid under CGLIB proxy!public final void finalMethod() {}

Similar non-transactional methods call transaction methods

public void methodA() {
    methodB(); // Transaction invalidation}
@Transactional
public void methodB() {}

Performance considerations

  • Agent creation increases startup time
  • Each transaction method call has an interception overhead
  • Long transactions will occupy database connections

This is the end of this article about the in-depth analysis of Spring @Transactional self-calling problem. For more related Spring @Transactional self-calling content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!