1. 事務的概念與特性
事務指的是邏輯上的一組操作,這組操作要麼全部成功,要麼全部失敗;用統一的機制來處理不同數據訪問技術的事務處理;
特性 | 描述 |
---|---|
原子性-atomicity | 事務中的各個操作不可單獨執行,要麼整體發生,要麼整體不發生 |
一致性-consistency | 事務執行前後的數據完整性必需保持一致 |
隔離性-isolation | 事務執行過程中不應該被其他事務干擾,多個併發事務之間的數據要互相隔離 |
持久性-durability | 一個事務一旦提交,數據庫中數據的改變就是永久性的 |
2. 事務管理 API
由 Spring 提供常用的 3 個 API 實現事務的管理
2.1 PlatformTransactionManager-事務管理器
常用事務 | 描述 |
---|---|
org.springframework.jdbc.datasource.DataSourceTransactionManager | Spring JDBC 或 Batis 進行持久化數據使用 |
org.springframework.orm.hibernate3.HibernateTransactionManager | Hiberbate 3.0 版本進行持久化數據使用 |
2.2 TransactionDefinition-事務定義信息
隔離級別 | 描述 |
---|---|
READ_UNCOMMITED | 最低隔離級別,充許別外一個事務可以看到這個事務未提交的數據。這種隔離級別會產生髒讀,不可重複讀和幻像讀 |
READ_COMMITTED | 保證一個事務修改的數據提交後才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的數據。這種事務隔離級別可以避免髒讀出現,但是可能會出現不可重複讀和幻像讀 |
REPEAtABLE_READ | 防止髒讀,不可重複讀。但是可能出現幻像讀。它除了保證一個事務不能讀取另一個事務未提交的數據外,還保證了避免下面的情況產生(不可重複讀) |
SERIALIZABLE | 花費最高代價但是最可靠的事務隔離級別,事務被處理爲順序執行。除了防止髒讀,不可重複讀外,還避免了幻像讀 |
傳播行爲 | 描述 |
---|---|
REQUIRED | 支持當前事務,如果不存在則創建 |
SUPPORTS | 支持當前事務,如果不存在就不使用 |
MANDATORY | 支持當前事務,如果不存在便拋出異常 |
REQUIRES_NEW | 如果有事務存在,掛起事務並創建新事物 |
NOT_SUPPORTED | 以非事務方式運行,如果事務存在則掛起當前事務 |
NEVER | 以非事務方式運行,如果事務存在則拋出異常 |
NESTED | 如果當前事務存在,則嵌套事務執行 |
2.3 TransactionStatus-事務狀態表現形式
3. 事務管理方式
3.1 編程式事務管理
- 業務類實現.class
public class ServiceImpl{
// 注入事務管理的模板
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate t){
this.transactionTemplate = t;
}
// 某個測試業務方法
public void tansactionTest(){
transactionTemplate.execute(new TransactionCallbackWithoutResult()){
@Override
protected void doInTransactionWithResult(TransactionStatus transactionStatus){
// 此處可以開始執行事務中的相關操作
}
}
}
}
- 編輯配置文件.xml
<beans ...>
<!-- 配置c3p0連接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置事務管理器,關聯連接池 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事務管模板,事務包裝 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<!-- 業務類,模板應用 -->
<bean id="service" class="com...ServiceImpl">
<!-- 注入事務管理的模板 -->
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
</beans>
3.2 聲明式事務管理 - 推薦
3.2.1 基於 TransactionProxyFactoryBean 方式
需爲每個事務管理的類都配置一個 TransactionProxyFactoryBean 。需要引入兩包:
- com.springsource.org.aopalliance.jar
- spring-aop.jar
- 業務類實現.class
public class ServiceImpl{
// 某個測試業務方法
public void tansactionTest(){
// 此處可以開始執行事務中的相關操作
}
}
- 編輯配置文件.xml
<beans ...>
<!-- 配置c3p0連接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 業務類 -->
<bean id="service" class="com...ServiceImpl"></bean>
<!-- 配置事務管理器,關聯連接池 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 業務層代理-->
<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
<!-- 關聯目標對象 -->
<property name="target" ref="service"/>
<!-- 注入事務管理器 -->
<property name="transactionManager" ref="transactionManager"/>
<!-- 注入事務屬性,代替目標對象完成注入工作 -->
<property name="transactionAtteributes">
<props>
<!--
prop 格式:
PROPAGATION : 事務的傳播行爲;
ISOLATION : 事務的隔離級別;
readOnly : 只讀;
-Exception : 指定發生異常執行回滾;
+Exception : 指定發生異常依然提交事務,不自信回滾;
-->
<prop key"transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
3.2.2 基於 AspectJ 方式
只需在 xml 配置中實現事務的增強式管理,而對應的類無需任何操作。需要引入兩包:
- com.springsource.org.aspectj.weaver.jar
- spring-aspects.jar
- 業務類實現.class
public class ServiceImpl{
// 某個測試業務方法
public void tansactionTest(){
// 此處可以開始執行事務中的相關操作
}
}
- 編輯配置文件.xml
<beans ...>
<!-- 配置c3p0連接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 業務類 -->
<bean id="service" class="com...ServiceImpl"></bean>
<!-- 配置事務管理器,關聯連接池 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事務的通知:(事務增強) -->
<tx:advice id="txAdvice" transaction-manager"="transactionManager">
<tx:attributes>
<!--
propagation : 事務的傳播行爲;
isolation : 事務的隔離級別;
read-only : 只讀;
rollback-for : 指定發生異常執行回滾;
no-rollback-for: 指定發生異常依然提交事務,不自信回滾;
timeout : 過期信息;
-->
<tx:method name="transfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<!-- 設定切入點 -->
<aop:pointcut expression="execution(* com...ServiceImpl+.*(..))" id="pointcut"/>
<!-- 設定切面 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
</beans>
3.2.2 基於註解方式
除 xml 配置並開啓事務以外,還需要爲每個事務管理類添加相應的註解信息。
- 業務類實現.class
/*
propagation : 事務的傳播行爲;
isolation : 事務的隔離級別;
readOnly : 只讀;
rollbackFor : 指定發生異常執行回滾;
noRollbackFor : 指定發生異常依然提交事務,不自信回滾;
注意:方法亦可以加該註解,標識覆蓋類聲明的註解信息。
*/
@Transactional(propagation=Propagation.REQUIRED)
public class ServiceImpl{
// 某個測試業務方法
public void tansactionTest(){
// 此處可以開始執行事務中的相關操作
}
}
- 編輯配置文件.xml
<beans ...>
<!-- 配置c3p0連接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 業務類 -->
<bean id="service" class="com...ServiceImpl"></bean>
<!-- 配置事務管理器,關聯連接池 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 開啓註解事務,配置文件.class 可用 @EnableTransactionManagement 啓用事務 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>