Spring 事務管理的核心三要素——DataSource、TransactionManager、代理機制——前兩者隨數據訪問技術變化,後者決定事務攔截粒度與配置風格。本文梳理 Spring 2.5 時代五種主流配置方式,展示從繁瑣 XML 向聲明式註解演進的脈絡。
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
註:若用 JPA/JDBC,分別換成 EntityManagerFactory/DataSource 及對應 TransactionManager 實現。
特點:每個目標 Bean 需顯式包裝 TransactionProxyFactoryBean,屬性重複度高。
<bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="userDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
<property name="target" ref="userDaoTarget"/>
<property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao"/>
<property name="transactionAttributes">
<props><prop key="*">PROPAGATION_REQUIRED</prop></props>
</property>
</bean>
缺點:DAO 增加時需複製大量 XML,維護成本高。
特點:抽象父 Bean transactionBase 定義公共事務屬性,子 Bean 通過 parent="transactionBase" 繼承,僅需指定 target。
<bean id="transactionBase" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true" abstract="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props><prop key="*">PROPAGATION_REQUIRED</prop></props>
</property>
</bean>
<bean id="userDao" parent="transactionBase">
<property name="target" ref="userDaoTarget"/>
</bean>
優勢:減少重複配置,但本質仍是逐個 Bean 代理。
特點:使用 BeanNameAutoProxyCreator 按 Bean 名稱模式(如 *Dao)批量創建代理,攔截器 TransactionInterceptor 集中定義事務屬性。
<bean id="transactionInterceptor" 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>transactionInterceptor</value></list></property>
</bean>
<bean id="userDao" class="com.bluesky.spring.dao.UserDaoImpl">...</bean>
優勢:零侵入業務 Bean 定義,新增 DAO 自動生效。
<tx:advice> + <aop:config>(Schema 風格)特點:Spring 2.0+ 引入 tx/aop 命名空間,用切點表達式精準匹配攔截點,配置可讀性大增。
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="daoPointcut" expression="execution(* com.bluesky.spring.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="daoPointcut"/>
</aop:config>
優勢:聲明式 AOP 風格,切點表達式靈活控制攔截範圍,成為 XML 時代主流。
特點:<tx:annotation-driven/> 啟用 @Transactional 掃描,業務類直接加註解,零 XML 代理配置。
<context:component-scan base-package="com.bluesky"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
@Transactional
@Component("userDao")
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
public List<User> listUsers() {
return getSession().createQuery("from User").list();
}
}
優勢:配置最簡潔,註解與代碼共存,易維護,現代 Spring 應用標配。
| 方式 | 配置量 | 靈活度 | 適用場景 |
|---|---|---|---|
| 1. 獨立代理 | 極大 | 單 Bean 級精細 | 極少量 Bean、需極致差異化 |
| 2. 父 Bean 繼承 | 大 | 單 Bean 級 | 中小項目、XML 時代過渡方案 |
| 3. 自動代理 + 攔截器 | 中 | 按名稱模式批量 | 命名規範統一的傳統項目 |
| 4. tx:aop Schema | 中小 | 切點表達式任意匹配 | XML 配置主流項目、需精細控制 |
| 5. 全註解 | 極小 | 類/方法級註解控制 | 現代 Spring/Spring Boot 項目首選 |
@Transactional + @Service/@Repository,配合 Spring Boot 自動配置,零 XML。PROPAGATION_REQUIRED,根據業務設置 readOnly、isolation、timeout、rollbackFor。事務配置的演進史,本質上是 Spring 從「配置驅動」向「約定優於配置」、「註解驅動」演進的縮影。