1. 程式人生 > >詳解spring中的事務管理(程式設計式的事務管理,宣告式的事務管理)

詳解spring中的事務管理(程式設計式的事務管理,宣告式的事務管理)

spring提供的事務管理API

1. PlatformTransactionManager:平臺事務管理器.

	commit(TransactionStatus status) 
	getTransaction(TransactionDefinition definition) 
	rollback(TransactionStatus status) 

2. TransactionDefinition:事務定義

	ISOLation_XXX:事務隔離級別.
	PROPAGATION_XXX:事務的傳播行為.
	過期時間:

3. TransactionStatus:事務狀態

	是否一個新的事務
	事務是否已經提交

這三者之間的關係: PlatformTransactionManager通過TransactionDefinition設定事務相關資訊管理事務,管理事務過程中,產生一些事務狀態:狀態由TransactionStatus記錄.

PlatformTransactionManager:介面.
Spring為不同的持久化框架提供了不同PlatformTransactionManager介面實現

1. org.springframework.jdbc.datasource.DataSourceTransactionManager :
使用Spring JDBC或iBatis 進行持久化資料時使用

2.

org.springframework.orm.hibernate3.HibernateTransactionManager:
使用Hibernate3.0版本進行持久化資料時使用

spring支援的兩種事務管理:

1. 程式設計式的事務管理:
在實際中很少用到。 通過Transaction手動管理事務

2. 宣告式的事務管理:
在實際中推薦使用(程式碼侵入量少),spring的宣告式事務管理是通過AOP實現的。

程式設計式的事務管理:

	<!-- 業務層類 -->
	<bean id="accountService" class="org.westos.demo1.AccountServiceImpl"
>
<!-- 在業務層注入Dao --> <property name="accountDao" ref="accountDao"/> </bean> <!-- 持久層類 --> <bean id="accountDao" class="org.westos.demo1.demo1.AccountDaoImpl"> <!-- 注入連線池的物件,通過連線池物件建立模板. --> <property name="dataSource" ref="dataSource"/> </bean>

需要事務管理器:真正管理事務物件.

  • Spring提供了事務管理的模板(工具類.)

第一步: 配置事務管理器

<!-- 配置事務管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 需要注入連線池,通過連線池獲得連線 -->
		<property name="dataSource" ref="dataSource"/>
	</bean>

第二步:配置事務模板類(TransactionTemplate)

	<!-- 事務管理的模板 -->
	<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
		<property name="transactionManager" ref="transactionManager"/>
	</bean>

第三步:在業務層注入模板:(通過模板管理事務)

	<!-- 業務層類 -->
	<bean id="accountService" class="org.westos.demo1.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);
			}
		});
	}

缺點: 程式碼量增加,程式碼有侵入性。

宣告式事務管理

1. 原始方式(基於TransactionProxyFactoryBean)

原理:spring的配置檔案對業務中需要進行事務管理的類生成一個TransactionProxyFactoryBean代理物件,來進行事務管理。

第一步:建立事務管理器:

	<!-- 事務管理器 -->
	<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>

第三步:編寫測試類:

@Autowired
//注意注入的是代理物件
@Qualifier("accountServiceProxy")
private AccountService accountService;

public void test1(){
	accountService.in(from,money);
}

缺點: 就是需要為每一個管理事務的類生成代理.需要為每個類都需要進行配置.

2.在(1)中的原始方式上有所改進(自動代理.基於切面):
原理:同樣和(1)中一樣也是生成一個代理物件來實現事務管理,但是使用了自動代理這樣就改進了(1)中的缺點,不需要每一個需要事務管理的類都配置生成代理物件。

第一步:配置事務管理器:

	<!-- 事務管理器 -->
	<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:config>
		<!-- 定義切點:哪些類的哪些方法應用增強 -->
		<aop:pointcut expression="execution(* org.westos.demo1.AccountService+.*(..))" id="mypointcut"/>
		<!-- 定義切面: -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="mypointcut"/>
	</aop:config>

3:基於註解的宣告式事務管理:

第一步:配置事務管理器:

	<!-- 事務管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>

第二步:啟用事務管理的註解:

	<!-- 開啟註解的事務管理 -->
	<tx:annotation-driven />

第三步:在業務類中所需要事務管理的方法上使用註解:

@Transactional
	//註解中有屬性值:
	//isolation
	//propagation
	// readOnly

@Transactional註解詳解:
預設情況下,只有方法出現的 是RuntimeException或Error以及它們的子類時(未檢查異常),才會導致事務回滾

如果要改變預設情況
@Transactional(rollbackFor=異常類.class)
那麼方法如果出現了該異常,或該異常的子類異常時,就會回滾

@Transactional(noRollbackFor=異常類.class)
當遇到這種異常時,不會回滾事務

最後要注意的是,在業務方法中不要自己try-catch捕獲異常,否則spring無法自動回滾事務

@Transactional(isolation = 隔離級別)

@Transactional(timeout = 超時時間(秒))

@Transactional(readOnly = true|false) true表示只讀(只有查詢) false(會有增刪改)設定為true,效能會有所提升,但是底層資料庫驅動支援(對mysql支援)