目標
1、事務回顧 :基本概念
2、Spring事務管理的一組API :通過api管理spring事務
3、Spring的編程式事務管理
4、Spring的聲明式事務管理
1、事務回顧:
· 什麼是事務?
事務指的是邏輯上的一組操作,這組操作要麼全部成功,要不全部失敗
·事務的特性:
原子性:原子性是指事務是一個不可分割的工作單位,事物中的操作要麼都發生,要麼都不發生
一致性:一致性指事務前後數據的完整性必須保持一致
隔離性:隔離性指多個用戶併發訪問數據庫時,一個用戶的事務不能被其他用戶的事務所幹擾,多個併發事務之間數據要互相隔離 (可設置隔離級別)
持久性:持久性是指一個事物一旦被提交,他對數據庫中數據的改變就是永久性的,即使數據庫發生故障也不應該對其有任何影響
· Spring 事務管理高層抽象主要包括3個接口
· Platform TransactionManager 事務管理器
管理事務— 提交、回滾
Spring爲不同的持久化框架提供了不同PlatformTransactoinManager接口實現
· TransactionDefinition 事務定義信息(隔離、傳播、超時、只讀)
事務定義信息—隔離級別、傳播行爲、是否超時、是否只讀
如果不考慮隔離性,會引發安全問題如下:
髒讀:
一個事務讀取了領一個事務改寫但還未提交的數據,如果這些數據被回滾,則讀到的數據是無效的。
不可重複讀:
在同一事務中,多次讀取同一數據返回的結果有所不同
幻讀:
一個事務讀取了幾行記錄後,另一個事務插入一些記錄,幻讀就發生了。
再後來的查詢中,第一個事務就會發現有些原來沒有的記錄
傳播行爲:
· TransactionStatus 事務具體運行狀態
運行狀態—是不是提交、有沒有保存點、是不是新事務
Spring 支持兩種方法的事務管理
-編程式的事務管理
· 在實際應用中很少使用
· 通過TransactionTemplate手動管理事務
· 在AccountService中使用TransactionTemplate
· TransactionTemplate依賴DataSourceTransactionManager
· DataSourceTransactionManager依賴DataSource構造
//注入轉賬的Dao的類
private AccountDao accountDao;
//注入事務管理的模板
private TransactionTemplate transactionTemplate;
/***
* Java
* @param out 轉出賬號
* @param in 轉入賬號
* @param money 轉出金額
*/
@Override
public void transfer(final String out, final String in, final Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.outMoney(out, money);
//int i=1/0;
accountDao.inMoney(in, money);
}
});
}
Spring 支持兩種方法的事務管理
-編程式的事務管理
· 在實際應用中很少使用
· 通過TransactionTemplate手動管理事務
· 在AccountService中使用TransactionTemplate
· TransactionTemplate依賴DataSourceTransactionManager
· DataSourceTransactionManager依賴DataSource構造
<!-- applicationContext.xml -->
<!-- 引入外部屬性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置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="accountService" class="cn.muke.spring.demo1.AccountServiceImpl">
<property name="accountDao" ref="accountDao" />
<!-- 注入事務的模板 -->
<property name="transactionTemplate" ref="transactionTemplate" />
</bean>
<!-- 配置Dao層類 -->
<bean id="accountDao" class="cn.muke.spring.demo1.AccountDaoImpl">
<!-- 注入連接池 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事務管理器 -編程式事務 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入連接池 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置事務管理模板:Spring爲了簡化事務管理的代碼所提供的類 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<!-- 注入事務管理器 -->
<property name="transactionManager" ref="transactionManager" />
</bean>
-使用XML配置聲明式事務
· 開發中推薦使用(代碼侵入性最小)
· Spring的聲明式事務是通過AOP實現
/***
* 測試
* 轉賬案例測試類
* @author smallearly
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo1 {
@Resource(name="accountService")
private AccountService accountService;
@Test
public void demo1(){
accountService.transfer("aaa", "bbb", 200d);
}
}
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<!-- 引入外部屬性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置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="accountService" class="cn.muke.spring.demo2.AccountServiceImpl">
<property name="accountDao" ref="accountDao" />
</bean>
<!-- 配置Dao層類 -->
<bean id="accountDao" class="cn.muke.spring.demo2.AccountDaoImpl">
<!-- 注入連接池 -->
<property name="dataSource" ref="dataSource"></property>
</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="accountService" />
<!-- 注入事務管理器 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 注入事務屬性 -->
<property name="transactionAttributes">
<props>
<!-- prop的格式
* PROPAGATION :事務的傳播行爲
* ISOLATION :事務的隔離級別
* readOnly :只讀(不能 修改、插入、刪除)
* -Exception :發生什麼異常回滾事務
* +Exception :發生什麼異常不回滾事務
-->
<prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop>
</props>
</property>
</bean>
</beans>