文檔版本 | 開發工具 | 測試平臺 | 工程名字 | 日期 | 作者 | 備註 |
---|---|---|---|---|---|---|
V1.0 | 2016.06.24 | lutianfei | none |
事務
- 事務:是邏輯上一組操作,要麼全都成功,要麼全都失敗.
事務特性:ACID
- 原子性:事務不可分割
- 一致性:事務執行的前後,數據完整性保持一致.
- 隔離性:一個事務執行的時候,不應該受到其他事務的打擾
- 持久性:一旦結束,數據就永久的保存到數據庫.
如果不考慮隔離性:
- 髒讀:一個事務讀到另一個事務未提交數據
- 不可重複讀:一個事務讀到另一個事務已經提交數據(update)導致一個事務多次查詢結果不一致
- 虛讀:一個事務讀到另一個事務已經提交數據(insert)導致一個事務多次查詢結果不一致
事務的隔離級別:
- 未提交讀:以上情況都有可能發生。
- 已提交讀:避免髒讀,但不可重複讀,虛讀是有可能發生。
- 可重複讀:避免髒讀,不可重複讀,但是虛讀有可能發生。
- 串行的:避免以上所有情況.
Spring中事務管理概述
分層開發:事務處在Service層.
Spring事務管理高層抽象主要包括3個接口:
PlatformTransactionManager:平臺事務管理器.
- commit(TransactionStatus status)
- getTransaction(TransactionDefinition definition)
- rollback(TransactionStatus status)
TransactionDefinition:事務定義信息(隔離、傳播、超時、只讀)
- ISOLation_XXX:事務隔離級別.
- PROPAGATION_XXX:事務的傳播行爲.(不是JDBC中有的,爲了解決實際開發問題.)
- 過期時間
TransactionStatus:事務具體運行狀態
- 是否有保存點
- 是否一個新的事務
- 事務是否已經提交
- 關係 :
PlatformTransactionManager
通過TransactionDefinition
設置事務相關信息管理事務,管理事務過程中,產生一些事務狀態:狀態由TransactionStatus
記錄.
事務管理API詳解
PlatformTransactionManager接口
- Spring爲不同的持久化框架提供了不同PlatformTransactionManager接口實現
- org.springframework.jdbc.datasource.DataSourceTransactionManager : 使用Spring JDBC或 iBatis 進行持久化數據時使用
- org.springframework.orm.hibernate3.HibernateTransactionManager : 使用Hibernate3.0版本進行持久化數據時使用
- org.springframework.orm.jpa.JpaTransactionManager 使用JPA進行持久化時使用
- org.springframework.jdo.JdoTransactionManager 當持久化機制是Jdo時使用
- org.springframework.transaction.jta.JtaTransactionManager 使用一個JTA實現來管理事務,在一個事務跨越多個資源時必須使用
TransactionDefinition
- 事物的隔離級別
- ISOLATION_DEFAULT:默認級別
- Mysql repeatable_read
- oracle read_commited
- ISOLATION_READ_UNCOMMITTED
- ISOLATION_READ_COMMITTED
- ISOLATION_REPEATABLE_READ
- ISOLATION_SERIALIZABLE
事務的傳播行爲: 不是JDBC事務管理,用來解決實際開發的問題.
- 傳播行爲:解決業務層之間的調用的事務的關係.
- PROPAGATION_REQUIRED :支持當前事務,如果不存在 就新建一個
- A,B 如果A有事務,B使用A的事務,如果A沒有事務,B就開啓一個新的事務.(A,B是在一個事務中。)
- PROPAGATION_SUPPORTS : 支持當前事務,如果不存在,就不使用事務
- A,B 如果A有事務,B使用A的事務,如果A沒有事務,B就不使用事務.
- PROPAGATION_MANDATORY :支持當前事務,如果不存在,拋出異常
- A,B 如果A有事務,B使用A的事務,如果A沒有事務,拋出異常.
- PROPAGATION_REQUIRES_NEW 如果有事務存在,掛起當前事務,創建一個新的事務
- A,B 如果A有事務,B將A的事務掛起,重新創建一個新的事務.(A,B不在一個事務中.事務互不影響.)
- PROPAGATION_NOT_SUPPORTED 以非事務方式運行,如果有事務存在,掛起當前事務
- A,B 非事務的方式運行,A有事務,就會掛起當前的事務.
- PROPAGATION_NEVER 以非事務方式運行,如果有事務存在,拋出異常
- PROPAGATION_NESTED 如果當前事務存在,則嵌套事務執行
- 基於SavePoint技術.
- A,B A有事務,A執行之後,將A事務執行之後的內容保存到SavePoint.B事務有異常的話,用戶需要自己設置事務提交還是回滾.
常用:(重點)
- PROPAGATION_REQUIRED
- PROPAGATION_REQUIRES_NEW
- PROPAGATION_NESTED
Spring的事務管理
- Spring的事務管理分成兩類
- 編程式事務管理
- 通過TransactionTemplate手動管理事務
- 聲明式事務管理
- Spring的聲明式事務是通過AOP實現的
- 編程式事務管理
事務操作的環境搭建
- 創建數據表account
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`money` double DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `account` VALUES ('1', 'aaa', '1000');
INSERT INTO `account` VALUES ('2', 'bbb', '1000');
INSERT INTO `account` VALUES ('3', 'ccc', '1000');
創建一個web項目
- 導入相應jar包
- 引入配置文件
- applicationContext.xml、log4j.properties、jdbc.properties
編寫DAO注入 注入JdbcTemplate
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
/**
* 轉出的方法
* @param from :轉出的人
* @param money :要轉賬金額
*/
public void out(String from, Double money) {
String sql = "update account set money = money - ? where name = ?";
this.getJdbcTemplate().update(sql, money,from);
}
/**
* 轉出的方法
* @param to :轉入的人
* @param money :要轉賬金額
*/
public void in(String to, Double money) {
String sql = "update account set money = money + ? where name = ?";
this.getJdbcTemplate().update(sql, money , to);
}
}
- 編寫Service注入DAO
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
/**
* 轉賬的方法
*
* @param from
* :從哪轉出
* @param to
* :轉入的人
* @param money
* :轉賬金額
*/
public void transfer(final String from, final String to, final Double money) {
accountDao.out(from, money);
// int d = 1 / 0;
accountDao.in(to, money);
}
}
- 在Spring中註冊
<!-- 業務層類 -->
<bean id="accountService" class="cn.itcast.spring3.demo1.AccountServiceImpl">
<!-- 在業務層注入Dao -->
<property name="accountDao" ref="accountDao"/>
<!-- 在業務層注入事務的管理模板 -->
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
<!-- 持久層類 -->
<bean id="accountDao" class="cn.itcast.spring3.demo1.AccountDaoImpl">
<!-- 注入連接池的對象,通過連接池對象創建模板. -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 事務管理的模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<!-- 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 需要注入連接池,通過連接池獲得連接 -->
<property name="dataSource" ref="dataSource"/>
</bean>
手動編碼的方式完成事務管理
- 需要事務管理器:真正管理事務對象.
Spring提供了事務管理的模板(工具類)
第一步:註冊事務管理器
<!-- 配置事務管理器 -->
<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="accountService" class="cn.itcast.spring3.demo1.AccountServiceImpl">
<!-- 在業務層注入Dao -->
<property name="accountDao" ref="accountDao"/>
<!-- 在業務層注入事務的管理模板 -->
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
- 第四步:在業務層代碼上使用模板:
public void transfer(final String from, final String to, final Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
accountDao.out(from, money);
int d = 1 / 0;
accountDao.in(to, money);
}
});
}
- 手動編碼方式缺點:
- 代碼量增加,代碼有侵入性.
- 代碼量增加,代碼有侵入性.
聲明式事務管理:(原始方式)
- 基於TransactionProxyFactoryBean.
導入:aop相應jar包.
第一步:註冊平臺事務管理器
<!-- 事務管理器 -->
<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 key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
- 第三步:編寫測試類:
- 千萬注意:注入的是代理對象
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class SpringTest2 {
@Autowired
@Qualifier("accountServiceProxy")
private AccountService accountService;
@Test
public void demo1(){
accountService.transfer("aaa", "bbb", 100d);
}
}
- prop格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
- 順序:傳播行爲、隔離級別、事務是否只讀、發生哪些異常可以回滾事務(所有的異常都回滾)、發生了哪些異常不回滾.
- 缺點:就是需要爲每一個管理事務的類生成代理.需要爲每個類都需要進行配置.
聲明式事務管理:(自動代理,基於切面)
基於XML配置方式的事務管理
第一步:導入相應jar包
- aspectj相關jar包
- com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
- spring-aspects-3.2.0.RELEASE.jar
第二步:引入相應約束
- aop、tx約束
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
- 第三步:註冊事務管理器
<!-- 事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
- 第四步:定義增強(事務管理)
<!-- 定義一個增強 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 增強(事務)的屬性的配置 -->
<tx:attributes>
<!--
isolation:DEFAULT :事務的隔離級別.
propagation :事務的傳播行爲.
read-only :false.不是隻讀
timeout :-1
no-rollback-for :發生哪些異常不回滾
rollback-for :發生哪些異常回滾事務
-->
<tx:method name="transfer"/>
</tx:attributes>
</tx:advice>
- 第五步:定義aop的配置(切點和通知的組合)
<!-- aop配置定義切面和切點的信息 -->
<aop:config>
<!-- 定義切點:哪些類的哪些方法應用增強 -->
<aop:pointcut expression="execution(* cn.itcast.spring3.demo3.AccountService+.*(..))" id="mypointcut"/>
<!-- 定義切面: -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypointcut"/>
</aop:config>
- 第六步:編寫測試類:
- 注入Service對象,不需要注入代理對象(生成這個類的時候,已經是代理對象.)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class SpringTest3 {
@Autowired
@Qualifier("accountService")
private AccountService accountService;
@Test
public void demo1(){
accountService.transfer("aaa", "bbb", 100d);
}
}
基於註解配置方式的事務管理
- 第一步:事務管理器
<!-- 事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
- 第二步:註解事務
<!-- 開啓註解的事務管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
- 第三步:在Service上使用註解
@Transactional
* 註解中有屬性值:
* isolation
* propagation
* readOnly