public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition);
void commit(TransactionStatus status);
void rollback(TransactionStatus status);
}
主流實現:
DataSourceTransactionManager(JDBC/MyBatis)HibernateTransactionManagerJtaTransactionManager(分佈式/JTA)JdoTransactionManagerDataSourceTransactionManager tm = new DataSourceTransactionManager(dataSource);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = tm.getTransaction(def);
try {
jdbcTemplate.update("INSERT ...");
jdbcTemplate.update("INSERT ... 故意寫錯 SQL");
tm.commit(status);
} catch (DataAccessException e) {
tm.rollback(status);
throw e;
}
TransactionTemplate template = new TransactionTemplate(tm);
template.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
jdbcTemplate.update("INSERT ...");
// 異常自動回滾,正常自動提交
}
});
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="userDAO" class="com.example.UserDAO">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="userDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target" ref="userDAO"/>
<property name="transactionManager" ref="txManager"/>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED,-MyCheckedException</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
使用時注入 userDAOProxy 而非 userDAO。
<bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="txManager"/>
<property name="transactionAttributes">
<props>
<prop key="com.example.UserDAO.insert*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="userDAOProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userDAO"/>
<property name="interceptorNames"><list><value>txInterceptor</value></list></property>
<property name="proxyInterfaces"><value>com.example.IUserDAO</value></property>
</bean>
此時直接注入 userDAO(被代理後),配置與業務代碼完全分離。
PROPAGATION_REQUIRED:有事務加入,無則新建(最常用)。readOnly:優化提示,適用於唯讀查詢。-Exception:遇到該檢查型異常回滾;+Exception:遇到該異常提交。RuntimeException / Error。聲明式事務是 Spring 最迷人特性之一:事務邊界集中配置,業務代碼純淨無污染,切換策略只改 XML/註解。