一.聲明式事務實現
- 將編程式事務章節中applicationContext.xml修改下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- 加載jdbc.property -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
<!-- 數據源配置, 使用DBCP數據庫連接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- Connection Info -->
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- Connection Pooling Info -->
<property name="maxActive" value="3"/>
<property name="defaultAutoCommit" value="false"/>
<!-- 連接Idle一個小時后超時 -->
<property name="timeBetweenEvictionRunsMillis" value="3600000"/>
<property name="minEvictableIdleTimeMillis" value="3600000"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="abstractDao" abstract="true">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="userDao" class="transaction.dao.UserDaoImp" parent="abstractDao"/>
<bean id="addressDao" class="transaction.dao.AddressDaoImp" parent="abstractDao"/>
<bean id="userService" class="transaction.service.UserServiceImp">
<property name="addressService" ref="addressService"/>
<property name="userDao" ref="userDao"/>
</bean>
<bean id="addressService" class="transaction.service.AddressServiceImp">
<property name="addressDao" ref="addressDao"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="*" propagation="REQUIRED" isolation="READ_COMMITTED" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* transaction.service.*Imp.*(..))" id="serviceMethod" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
</aop:config>
</beans>
聲明式事務通過AOP代理方式實現事務管理,利用環繞通知TransactionInterceptor實現事務的開啟及關閉,而TransactionProxyFactoryBean內部也是通過該環繞通知實現的,因此可以認為是<tx:tags/>幫你定義了TransactionProxyFactoryBean,從而簡化事務管理
二.<tx:advice/>配置
<tx:advice id="……" transaction-manager="……">
<tx:attributes>
<tx:method name="……"
propagation=" REQUIRED"
isolation="READ_COMMITTED"
timeout="-1"
read-only="false"
no-rollback-for=""
rollback-for=""/>
……
</tx:attributes>
</tx:advice>
- <tx:advice>:id用于指定此通知的名字, transaction-manager用于指定事務管理器,默認的事務管理器名字為“transactionManager”;
- <tx:method>:用于定義事務屬性即相關聯的方法名;
name:定義與事務屬性相關聯的方法名,將對匹配的方法應用定義的事務屬性,可以使用“”通配符來匹配一組或所有方法,如save將匹配以save開頭的方法,而“”將匹配所有方法;
propagation:事務傳播行為定義,默認為“REQUIRED”,表示Required,其值可以通過TransactionDefinition的靜態傳播行為變量的“PROPAGATION_”后邊部分指定,如“TransactionDefinition.PROPAGATION_REQUIRED”可以使用“REQUIRED”指定;
isolation: 事務隔離級別定義;默認為“DEFAULT”,其值可以通過TransactionDefinition的靜態隔離級別變量的“ISOLATION_”后邊部分指定,如“TransactionDefinition. ISOLATION_DEFAULT”可以使用“DEFAULT”指定:
timeout:事務超時時間設置,單位為秒,默認-1,表示事務超時將依賴于底層事務系統;
read-only:事務只讀設置,默認為false,表示不是只讀;
rollback-for:需要觸發回滾的異常定義,以“,”分割,默認任何RuntimeException 將導致事務回滾,而任何Checked Exception 將不導致事務回滾;異常名字定義和TransactionProxyFactoryBean中含義一樣
no-rollback-for:不被觸發進行回滾的 Exception(s);以“,”分割;異常名字定義和TransactionProxyFactoryBean中含義一樣;
三.多事務語義配置
- 明式事務配置的最佳實踐
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="merge*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="put*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="count*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="list*" propagation="SUPPORTS" read-only="true" />
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* transaction.service.*Imp.*(..))" id="serviceMethod" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
</aop:config>
四.@Transactional實現事務管理
- @Transactional配置
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED)
public void save(final User user){
userDao.save(user);
user.getAddress().setUserId(user.getId());
addressService.save(user.getAddress());
throw new RuntimeException();
}
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED,readOnly=true)
public int countAll() {
return userDao.countAll();
}
- 開啟@Transactional注解支持
<tx:annotation-driven proxy-target-class="false" transaction-manager="transactionManager" order="1"/>
Spring提供的<tx:annotation-driven/>用于開啟對注解事務管理的支持,從而能識別Bean類上的@Transactional注解元數據,其具有以下屬性:
transaction-manager: 指定事務管理器名字,默認為transactionManager,當使用其他名字時需要明確指定;
proxy-target-class: 表示將使用的代碼機制,默認false表示使用JDK代理,如果為true將使用CGLIB代理
order: 定義事務通知順序,默認Ordered.LOWEST_PRECEDENCE,表示將順序決定權交給AOP來處理。Spring使用@Transaction來指定事務屬性,可以在接口、類或方法上指定,如果類和方法上都指定了@Transaction,則方法上的事務屬性被優先使用,具體屬性如下:
value: 指定事務管理器名字,默認使用<tx:annotation-driven/>指定的事務管理器,用于支持多事務管理器環境;
propagation:指定事務傳播行為,默認為Required,使用Propagation.REQUIRED指定;
isolation:指定事務隔離級別,默認為“DEFAULT”,使用Isolation.DEFAULT指定;
readOnly:指定事務是否只讀,默認false表示事務非只讀;
timeout:指定事務超時時間,以秒為單位,默認-1表示事務超時將依賴于底層事務系統;
rollbackFor:指定一組異常類,遇到該類異常將回滾事務;
rollbackForClassname:指定一組異常類名字,其含義與<tx:method>中的rollback-for屬性語義完全一樣;
noRollbackFor:指定一組異常類,即使遇到該類異常也將提交事務,即不回滾事務;
noRollbackForClassname:指定一組異常類名字,其含義與<tx:method>中的no-rollback-for屬性語義完全一樣;