spring的事務管理筆記

什麼是事務:java

事務指的是邏輯上的一組操做,這組操做要麼所有成功,要麼所有失敗。mysql

事務的特性:git

原子性,隔離性,一致性,持久性。spring

原子性:指的是事務是一個不可分割的工做單位,事務的發生要麼所有發生,要麼所有都不發生。sql

隔離性:指的是當多個用戶併發訪問數據庫時,一個用戶的事務不能被其餘用戶的事務所幹擾,多個併發事務之間數據要相互隔離。數據庫

一致性:指事務發生後,先後的數據完整性必須保持一致。express

持久性:當事務必定提交,他對數據庫中的數據的改變是永久的,即便數據庫發生故障也不該該對其有任何影響。編程


Spring 事務管理高層抽象主要包括了3個接口:後端

  1. platFormTransactionManager    事務管理器併發

  2. TransactionDefinition 事務定義信息(隔離,傳播,超時,只讀)

  3. TransactionStatus 事務具體運行狀態

(1)platFormTranscationManager 是一個接口 有不少針對不一樣持久層的框架去選擇不一樣的事務管理器

                         事務 說明
org.sprinframework.jdbc.datasource.DataSourceTransactionManager
使用Spring JDBC或iBatis進行持久化數據時使用
org.springframework.orm.hibernate3.HibernateTranscationManager 使用Hiber3.0版本進行持久化數據時使用
org.springframework.orm.jpa.JpaTranscationManager 使用JPA進行持久化時使用
org.springframework.jdo.JdoTranscationManager
當持久化機制是jdo時使用
org.springframework.transaction.jta.JtaTranscationManager 使用一個JTA實現來管理事務,在一個事務跨越多個資源時必須使用

(2)TranscationDefinition

TransactionDefinition接口的常量中ISOLATION_開頭的表示事物的隔離級別(4種)

沒有的話隔離級別,會出現的問題:

髒讀:一個事務讀取到另一個事務改寫但還未提交的數據。若是這些數據被回滾,則讀到的數據是無效的。

不可重複讀:在同一個事務中,讀到了另外一個事務已經提交更新的數據返回結果不同,致使這個事務中先後的查詢結果不一致。

虛讀或幻讀:一個事務讀取一些數據以後,另外一個事務插入了一些記錄,而致使這個事務中查詢的數據不一致。(第二次讀取,會讀取到插入後一些數據)

看了上面的解釋,感受不可重複讀和幻讀很相似。

特地查一下資料:

        不可重複讀的重點在修改,你先後讀取到的數據是不同。

        例子(我隨便想的,可能不對):事務1,a查詢卡里有1000元,事務2,有人轉500到你的卡里,事務1尚未結束,它再次查詢卡里的金額,顯示爲1500元。同一個事務中先後讀取的信息不一致。

       幻讀的重點在新增或刪除,一樣的條件, 第1次和第2次讀出來的記錄數不同。

        例子(網上找的):目前工資爲1000的員工有10人。 事務1,讀取全部工資爲1000的員工。 這時另外一個事務向employee表插入了一條員工記錄,工資也爲1000 ,事務1再次讀取全部工資爲1000的員工 共讀取到了11條記錄,這就產生了幻像讀。

隔離級別 含義
DEFAULT 使用後端數據庫默認的隔離級別(spring中的選擇項)
READ_UNCOMMITED 容許你讀取還未提交的改變了得數據,可能致使髒讀,幻讀,不可重複讀
READ_COMMITED 容許在併發事務已經提交讀取,可防止髒讀,但幻讀和不可重複讀仍可發生
REPEATABLE_READ 對相同字段的屢次讀取是一致的,除非數據被事務自己改變。可防止髒,不可重複讀,但幻讀仍可發生
SERIALIZABLE 徹底服從ACID(數據庫事務四要素)的隔離級別,確保不發生髒,幻,不可重複讀。這在全部的隔離級別中是最慢的。他是典型的經過徹底鎖定在事務中涉及的數據表完成的。

mysql默認採用REPEATABLE_READ隔離級別

oracle默認採用READ_COMMITED隔離級別

TransactionDefinition接口的常量中PROPAGATION開頭的表示事物的傳播行爲(7種)

  當出現複雜狀況時,好比某一個業務調用的業務層中的另外二個業務,每一個業務都裏面都有事務。

  事務的傳播行爲:解決業務層方法之間的相互調用的問

事務傳播行爲類型 說明
PROPAGATION_REQUIRED 支持當前事務,若是不存在,就新建一個
PROPAGATION_SUPPORTS  支持當前事務,若是不存在,就不使用事務
PROPAGATION_MANDATORY  支持當前事務,若是不存在,拋出異常
PROPAGATION_REQUIRES_NEW  若是有事務存在,掛起當前事務,建立一個新的事務
PROPAGATION_NOT_SUPPORTED  以非事務運行,若是有事務存在,掛起當前事務
PROPAGATION_NEVER  以非事務運行,若是有事務存在,拋出異常
PROPAGATION_NESTED  若是當前事務存在,則嵌套事務存在

 Spring事務管理

Spring支持兩種方式事務管理

--編程式的事務管理

  • 在實際應用中不多使用

  • 經過TranscationTemplate手動管理事務  

--使用xml配置聲明式事務

  • 開發中推薦使用(代碼侵入性最小)

  • Spring的聲明式事務時經過aop實現的                                                                                                                                                                                                                                                                                 

用轉帳系統的事務管理。     

  編程式的事務管理,在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="com.spring.demo1.AccountServiceImpl">
		<property name="accountDao" ref="accountDao" />
		<!-- 注入事務管理的模板 -->
		<property name="transactionTemplate" ref="transactionTemplate" />
	</bean>
	
	<!-- 配置DAO類(簡化,會自動配置JdbcTemplate) -->
	<bean id="accountDao" class="com.spring.demo1.AccountDaoImpl">
		<property name="dataSource" ref="dataSource" />
	</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>

   在轉帳業務上 注入事務管理的模板   

@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);
			}
		});
	}

基於代理的聲明式的事務管理

<!-- 配置事務管理器 -->
	<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	:事務的傳播行爲
						* ISOTATION		:事務的隔離級別
						* readOnly		:只讀
						* -EXCEPTION	:發生哪些異常回滾事務
						* +EXCEPTION 	:發生哪些異常不回滾事務
				 -->
				<prop key="transfer">PROPAGATION_REQUIRED</prop>
				<!-- <prop key="transfer">PROPAGATION_REQUIRED,readOnly</prop> -->
				<!-- <prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> -->
			</props>
		</property>
	</bean>

在轉帳業務上 

@Override
	public void transfer(String out, String in, Double money) {
		accountDao.outMoney(out, money);
		//int i = 1/0;
		accountDao.inMoney(in, money);
	}

使用XML配置聲明式的事務管理,基於tx/aop

<!-- 配置事務管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	
	<!-- 配置事務的增長  -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="transfer" propagation="REQUIRED"/>
			<!-- 
				propagation : 事務的傳播行爲
				isolation : 事務隔離級別
				read-only : 只讀
				rollback-for :發生那些異常回來
				no-rollback-for : 發生哪些一場不回滾
				timeout :過時信息
			 -->
		</tx:attributes>
	</tx:advice>
	
	<!-- 配置切面 -->
	<aop:config>
		<!-- 配置切入點 -->
		<aop:pointcut expression="execution(* com.spring.demo3.AccountService+.*(..))" id="pointcut1"/>
		<!-- 配置切面 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
	</aop:config>

業務代碼

@Override
	public void transfer(String out, String in, Double money) {
		accountDao.outMoney(out, money);
		int i = 1/0;
		accountDao.inMoney(in, money);
	}

基於註解的事務管理的方式

<!-- ==================================4.基於註解的的事務管理 =============================================== -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	
	<!-- 開啓註解事務 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>

業務代碼

/**
 * @Transactional 註解中的屬性:
 * propagation    :事務的傳播行爲
 * isolation      :事務的隔離級別
 * readOnly       :只讀
 * rollbackFor    :發生哪些異常回滾
 * noRollbackFor  :發生那些異常不回滾
 * @author mufeng
 *
 */
 	@Override
	public void transfer(String out, String in, Double money) {
		accountDao.outMoney(out, money);
		int i = 1/0;
		accountDao.inMoney(in, money);
	}

具體代碼:http://git.oschina.net/chenfwind/spring_transcation

相關文章
相關標籤/搜索