一個業務操作往往涉及多個 DAO 調用(如:扣款 + 記錄流水 + 發送通知)。若事務在 DAO 層,每個 DAO 獨立提交/回滾,無法保證業務原子性。Service 層作為業務邊界,統一開啟/提交/回滾事務,才能保證多表操作一致性。
每個 Bean 一個代理定義,配置冗餘,不推薦新專案使用。
abstract="true" 定義基類,子 Bean 繼承 parent="txBase"。減少重複但仍需逐個聲明。
<bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="txManager"/>
<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>*Service</value></list></property>
<property name="interceptorNames"><list><value>txInterceptor</value></list></property>
</bean>
通配符批量代理 Service 層,無需修改業務代碼。
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceMethods" expression="execution(* com.service..*Service.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"/>
</aop:config>
<tx:annotation-driven transaction-manager="txManager"/> <context:component-scan base-package="com.service"/>
@Service
@Transactional(rollbackFor = Exception.class) // 默認 REQUIRED
public class OrderService {
@Autowired OrderDao orderDao;
@Autowired AccountDao accountDao;
@Transactional(readOnly = true)
public Order getOrder(Long id) { return orderDao.findById(id); }
public void createOrder(Order order) {
accountDao.deduct(order.getUserId(), order.getAmount()); // DAO 1
orderDao.save(order); // DAO 2
// 任一異常,整體回滾
}
}
REQUIRED (默認):業務主流程,確保同一事務REQUIRES_NEW:日誌、審計、獨立提交SUPPORTS + readOnly=true:查詢方法,無事務開銷NESTED:保存點回滾(需 JDBC 支援)默認僅回滾 RuntimeException 和 Error。業務異常 (Checked Exception) 必須顯式聲明:
@Transactional(rollbackFor = {BizException.class, Exception.class})
public void transfer(...) throws BizException { ... }
@Transactional(readOnly = true) public ListlistOrders() { ... }
this.method() 繞過代理。@Autowired SelfService self 或拆分類。try-catch 未重拋,事務不回滾。throw new RuntimeException(e) 或 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。@Transactional("txManager2")。事務配置核心原則:Service 層統一、默認 REQUIRED、查詢 SUPPORTS+readOnly、業務異常顯式 rollbackFor、避免同類內部調用。