Resolving Transactional Annotation Failures in SSM Framework Integration

Developers integrating Spring, SpringMVC, and MyBatis often encounter scenarios where @Transactional annotations seemingly fail, resulting in persistent database changes despite runtime exceptions. Log files typically contain the warning: JDBC Connection will not be managed by Spring, indicating the transaction advisor never intercepted the method execution.

Typical Misconfiguration Pattern

The issue commonly arises from overlapping component-scan directives across the root and web application contexts. Consider this standard setup:

Root Context Configuration (applicationContext.xml):

<!-- Enabling annotation-driven transactions -->
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="primaryDataSource" />
</bean>

Service Layer Implementation:

@Service
public class FundTransferService {
    @Autowired
    private AccountDao accountDao;
    
    @Transactional(rollbackFor = Exception.class)
    public void processTransfer(Integer debitAccount, Integer creditAccount, Double transferAmount) {
        // Deduct from source account
        accountDao.adjustBalance(debitAccount, -transferAmount);
        System.out.println("Debited: " + transferAmount);
        
        // Simulate business logic exception
        if (transferAmount > 5000.0) {
            throw new IllegalStateException("Amount exceeds single transaction limit");
        }
        
        // Add to destination account
        accountDao.adjustBalance(creditAccount, transferAmount);
        System.out.println("Credited: " + transferAmount);
    }
}

Web Context Componnet Scanning (springmvc.xml):

<context:component-scan base-package="com.example.controllers,com.example.services" />

Underlying Container Hierarchy Issue

Spring's context architecture creates a parent-child relationship:

  • The ContextLoaderListener bootstraps the parent conatiner from applicationContext.xml
  • The DispatcherServlet initializes a child container from springmvc.xml
  • When the child container scans @Service components, it instantiates them before the parent container's transaction post-processor can apply AOP proxies
  • These unproxied service beans lack transaction interception and override the properly-configured parent beans

Resolution Strategy

Segregate component scanning responsibilities between contexts:

In the root application context, scan all service and repository components:

<context:component-scan base-package="com.example.services,com.example.repositories" />

In the web context, restrict scanning to controller components exclusively:

<context:component-scan base-package="com.example.controllers">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

This architectural separation ensures:

  1. Service beans initialize within the parent container where the transaction manager applies AOP advice
  2. Controller beans remain in the child container with access to web-specific features
  3. No bean definition conflicts occur between container hierarchies

Tags: Spring SpringMVC MyBatis Transactional aop

Posted on Mon, 06 Jul 2026 17:37:49 +0000 by paruby