無論哪種方式,Spring 事務配置永遠由三部分組成:
DataSourceTransactionManager / HibernateTransactionManager / JtaTransactionManager<bean id="userDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="target" ref="userDaoTarget"/>
<property name="proxyInterfaces" value="com.dao.UserDao"/>
<property name="transactionAttributes">
<props><prop key="*">PROPAGATION_REQUIRED</prop></props>
</property>
</bean>
缺點:Bean 多時配置爆炸,維護極其痛苦。
<bean id="txBase" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true" lazy-init="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props><prop key="*">PROPAGATION_REQUIRED</prop></props>
</property>
</bean>
<bean id="userDao" parent="txBase">
<property name="target" ref="userDaoTarget"/>
</bean>
改進:減少重複配置,但仍需為每個 Bean 顯式聲明。
<bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props><prop key="*">PROPAGATION_REQUIRED</prop></props>
</property>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames"><list><value>*Dao</value></list></property>
<property name="interceptorNames"><list><value>txInterceptor</value></list></property>
</bean>
優點:通配符批量代理,新增 Bean 無需配置。缺點:僅支援 Bean 名稱匹配,不支援切點表達式。
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="daoMethods" expression="execution(* com.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="daoMethods"/>
</aop:config>
優勢:強大的切點表達式(execution、within、@annotation 等),關注點分離清晰,Spring 2.0+ 標準做法。
<tx:annotation-driven transaction-manager="transactionManager"/> <context:component-scan base-package="com.service"/>
@Configuration
@EnableTransactionManagement
@ComponentScan("com.service")
public class TxConfig {
@Bean
public DataSource dataSource() { ... }
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
@Service
@Transactional // 類級別:所有 public 方法開啟事務
public class UserService {
@Autowired UserDao userDao;
@Transactional(readOnly = true) // 方法級別覆蓋:只讀優化
public User getById(Long id) { return userDao.findById(id); }
@Transactional(rollbackFor = Exception.class) // 指定回滾異常
public void register(User user) { userDao.save(user); }
}
| 方式 | 配置量 | 靈活度 | 可讀性 | 推薦場景 |
|---|---|---|---|---|
| 1. 獨立代理 | 極大 | 低 | 差 | 極少 Bean 的微型項目 |
| 2. 父 Bean 共享 | 大 | 中 | 中 | Spring 1.x 遺留項目維護 |
| 3. 自動代理攔截器 | 中 | 中(僅名稱匹配) | 中 | 命名規範嚴格、不想引入 AOP 命名空間 |
| 4. tx/aop 命名空間 | 小 | 高(切點表達式) | 好 | 傳統 XML 專案、需精細控制切點 |
| 5. 全注解 | 極小 | 最高(方法級覆蓋) | 最好 | 現代 Spring 專案首選 |
本質上,所有方式最終都生成
TransactionInterceptor織入目標 Bean。選擇哪種只是「配置風格」差異,運行時行為一致。