Spring事務配置的五種方式java
前段時間對Spring的事務配置作了比較深刻的研究,在此之間對Spring的事務配置雖然說也配置過,可是一直沒有一個清楚的認識。經過此次的學習發覺Spring的事務配置只要把思路理清,仍是比較好掌握的。
總結以下:
Spring配置文件中關於事務配置老是由三個組成部分,分別是DataSource、TransactionManager和代理機制這三部分,不管哪一種配置方式,通常變化的只是代理機制這部分。
DataSource、TransactionManager這兩部分只是會根據數據訪問方式有所變化,好比使用Hibernate進行數據訪問時,DataSource實際爲SessionFactory,TransactionManager的實現爲HibernateTransactionManager。
具體以下圖:spring
根據代理機制的不一樣,總結了五種Spring事務的配置方式,配置文件以下:
第一種方式:每一個Bean都有一個代理數據庫
<? 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" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd" > < bean id ="sessionFactory" class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" > < property name ="configLocation" value ="classpath:hibernate.cfg.xml" /> < property name ="configurationClass" value ="org.hibernate.cfg.AnnotationConfiguration" /> </ bean > <!-- 定義事務管理器(聲明式的事務) --> < bean id ="transactionManager" class ="org.springframework.orm.hibernate3.HibernateTransactionManager" > < property name ="sessionFactory" ref ="sessionFactory" /> </ bean > <!-- 配置DAO --> < bean id ="userDaoTarget" class ="com.bluesky.spring.dao.UserDaoImpl" > < property name ="sessionFactory" ref ="sessionFactory" /> </ bean > < bean id ="userDao" class ="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" > <!-- 配置事務管理器 --> < property name ="transactionManager" ref ="transactionManager" /> < property name ="target" ref ="userDaoTarget" /> < property name ="proxyInterfaces" value ="com.bluesky.spring.dao.GeneratorDao" /> <!-- 配置事務屬性 --> < property name ="transactionAttributes" > < props > < prop key ="*" > PROPAGATION_REQUIRED </ prop > </ props > </ property > </ bean > </ beans >
第二種方式:全部Bean共享一個代理基類express
<? 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" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd" > < bean id ="sessionFactory" class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" > < property name ="configLocation" value ="classpath:hibernate.cfg.xml" /> < property name ="configurationClass" value ="org.hibernate.cfg.AnnotationConfiguration" /> </ bean > <!-- 定義事務管理器(聲明式的事務) --> < bean id ="transactionManager" class ="org.springframework.orm.hibernate3.HibernateTransactionManager" > < property name ="sessionFactory" ref ="sessionFactory" /> </ bean > < bean id ="transactionBase" class ="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" lazy-init ="true" abstract ="true" > <!-- 配置事務管理器 --> < property name ="transactionManager" ref ="transactionManager" /> <!-- 配置事務屬性 --> < property name ="transactionAttributes" > < props > < prop key ="*" > PROPAGATION_REQUIRED </ prop > </ props > </ property > </ bean > <!-- 配置DAO --> < bean id ="userDaoTarget" class ="com.bluesky.spring.dao.UserDaoImpl" > < property name ="sessionFactory" ref ="sessionFactory" /> </ bean > < bean id ="userDao" parent ="transactionBase" > < property name ="target" ref ="userDaoTarget" /> </ bean > </ beans >
第三種方式:使用攔截器緩存
<? 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" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd" > < bean id ="sessionFactory" class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" > < property name ="configLocation" value ="classpath:hibernate.cfg.xml" /> < property name ="configurationClass" value ="org.hibernate.cfg.AnnotationConfiguration" /> </ bean > <!-- 定義事務管理器(聲明式的事務) --> < bean id ="transactionManager" class ="org.springframework.orm.hibernate3.HibernateTransactionManager" > < property name ="sessionFactory" ref ="sessionFactory" /> </ bean > < bean id ="transactionInterceptor" class ="org.springframework.transaction.interceptor.TransactionInterceptor" > < property name ="transactionManager" ref ="transactionManager" /> <!-- 配置事務屬性 --> < property name ="transactionAttributes" > < props > < prop key ="*" > PROPAGATION_REQUIRED </ prop > </ props > </ property > </ bean > < bean class ="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" > < property name ="beanNames" > < list > < value > *Dao </ value > </ list > </ property > < property name ="interceptorNames" > < list > < value > transactionInterceptor </ value > </ list > </ property > </ bean > <!-- 配置DAO --> < bean id ="userDao" class ="com.bluesky.spring.dao.UserDaoImpl" > < property name ="sessionFactory" ref ="sessionFactory" /> </ bean > </ beans >
第四種方式:使用tx標籤配置的攔截器服務器
<? 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" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" > < context:annotation-config /> < context:component-scan base-package ="com.bluesky" /> < bean id ="sessionFactory" class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" > < property name ="configLocation" value ="classpath:hibernate.cfg.xml" /> < property name ="configurationClass" value ="org.hibernate.cfg.AnnotationConfiguration" /> </ bean > <!-- 定義事務管理器(聲明式的事務) --> < bean id ="transactionManager" class ="org.springframework.orm.hibernate3.HibernateTransactionManager" > < property name ="sessionFactory" ref ="sessionFactory" /> </ bean > < tx:advice id ="txAdvice" transaction-manager ="transactionManager" > < tx:attributes > < tx:method name ="*" propagation ="REQUIRED" /> </ tx:attributes > </ tx:advice > < aop:config > < aop:pointcut id ="interceptorPointCuts" expression ="execution(* com.bluesky.spring.dao.*.*(..))" /> < aop:advisor advice-ref ="txAdvice" pointcut-ref ="interceptorPointCuts" /> </ aop:config > </ beans >
第五種方式:全註解session
<? 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" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" > < context:annotation-config /> < context:component-scan base-package ="com.bluesky" /> < tx:annotation-driven transaction-manager ="transactionManager" /> < bean id ="sessionFactory" class ="org.springframework.orm.hibernate3.LocalSessionFactoryBean" > < property name ="configLocation" value ="classpath:hibernate.cfg.xml" /> < property name ="configurationClass" value ="org.hibernate.cfg.AnnotationConfiguration" /> </ bean > <!-- 定義事務管理器(聲明式的事務) --> < bean id ="transactionManager" class ="org.springframework.orm.hibernate3.HibernateTransactionManager" > < property name ="sessionFactory" ref ="sessionFactory" /> </ bean > </ beans >
此時在DAO上需加上@Transactional註解,以下:併發
package com.bluesky.spring.dao; import java.util.List; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.stereotype.Component; import com.bluesky.spring.domain.User; @Transactional @Component( " userDao " ) public class UserDaoImpl extends HibernateDaoSupport implements UserDao { public List < User > listUsers() { return this .getSession().createQuery( " from User " ).list(); }  }
spring裏面事務的傳播屬性和 事務隔離級別dom
1、Propagation (事務的傳播屬性)工具
Propagation : key屬性肯定代理應該給哪一個方法增長事務行爲。這樣的屬性最重要的部份是傳播行爲。有如下選項可供使用:
PROPAGATION_REQUIRED--支持當前事務,若是當前沒有事務,就新建一個事務。這是最多見的選擇。
PROPAGATION_SUPPORTS--支持當前事務,若是當前沒有事務,就以非事務方式執行。
PROPAGATION_MANDATORY--支持當前事務,若是當前沒有事務,就拋出異常。
PROPAGATION_REQUIRES_NEW--新建事務,若是當前存在事務,把當前事務掛起。
PROPAGATION_NOT_SUPPORTED--以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。
PROPAGATION_NEVER--以非事務方式執行,若是當前存在事務,則拋出異常。
1: PROPAGATION_REQUIRED
加入當前正要執行的事務不在另一個事務裏,那麼就起一個新的事務
好比說,ServiceB.methodB的事務級別定義爲PROPAGATION_REQUIRED, 那麼因爲執行ServiceA.methodA的時候,
ServiceA.methodA已經起了事務,這時調用ServiceB.methodB,ServiceB.methodB看到本身已經運行在ServiceA.methodA
的事務內部,就再也不起新的事務。而假如ServiceA.methodA運行的時候發現本身沒有在事務中,他就會爲本身分配一個事務。
這樣,在ServiceA.methodA或者在ServiceB.methodB內的任何地方出現異常,事務都會被回滾。即便ServiceB.methodB的事務已經被
提交,可是ServiceA.methodA在接下來fail要回滾,ServiceB.methodB也要回滾
2: PROPAGATION_SUPPORTS
若是當前在事務中,即以事務的形式運行,若是當前再也不一個事務中,那麼就以非事務的形式運行
3: PROPAGATION_MANDATORY
必須在一個事務中運行。也就是說,他只能被一個父事務調用。不然,他就要拋出異常
4: PROPAGATION_REQUIRES_NEW
這個就比較繞口了。 好比咱們設計ServiceA.methodA的事務級別爲PROPAGATION_REQUIRED,ServiceB.methodB的事務級別爲PROPAGATION_REQUIRES_NEW,
那麼當執行到ServiceB.methodB的時候,ServiceA.methodA所在的事務就會掛起,ServiceB.methodB會起一個新的事務,等待ServiceB.methodB的事務完成之後,
他才繼續執行。他與PROPAGATION_REQUIRED 的事務區別在於事務的回滾程度了。由於ServiceB.methodB是新起一個事務,那麼就是存在
兩個不一樣的事務。若是ServiceB.methodB已經提交,那麼ServiceA.methodA失敗回滾,ServiceB.methodB是不會回滾的。若是ServiceB.methodB失敗回滾,
若是他拋出的異常被ServiceA.methodA捕獲,ServiceA.methodA事務仍然可能提交。
5: PROPAGATION_NOT_SUPPORTED
當前不支持事務。好比ServiceA.methodA的事務級別是PROPAGATION_REQUIRED ,而ServiceB.methodB的事務級別是PROPAGATION_NOT_SUPPORTED ,
那麼當執行到ServiceB.methodB時,ServiceA.methodA的事務掛起,而他以非事務的狀態運行完,再繼續ServiceA.methodA的事務。
6: PROPAGATION_NEVER
不能在事務中運行。假設ServiceA.methodA的事務級別是PROPAGATION_REQUIRED, 而ServiceB.methodB的事務級別是PROPAGATION_NEVER ,
那麼ServiceB.methodB就要拋出異常了。
7: PROPAGATION_NESTED
理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區別是,PROPAGATION_REQUIRES_NEW另起一個事務,將會與他的父事務相互獨立,
而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,若是父事務最後回滾,他也要回滾的。
而Nested事務的好處是他有一個savepoint。
ServiceA {
/**
*/
void methodA() {
try {
//savepoint
ServiceB.methodB(); //PROPAGATION_NESTED 級別
} catch (SomeException) {
// 執行其餘業務, 如 ServiceC.methodC();
}
}
}
也就是說ServiceB.methodB失敗回滾,那麼ServiceA.methodA也會回滾到savepoint點上,ServiceA.methodA能夠選擇另一個分支,好比
ServiceC.methodC,繼續執行,來嘗試完成本身的事務。
可是這個事務並無在EJB標準中定義。
2、Isolation Level(事務隔離等級):
一、Serializable:最嚴格的級別,事務串行執行,資源消耗最大;
二、REPEATABLE READ:保證了一個事務不會修改已經由另外一個事務讀取但未提交(回滾)的數據。避免了「髒讀取」和「不可重複讀取」的狀況,可是帶來了更多的性能損失。
三、READ COMMITTED:大多數主流數據庫的默認事務等級,保證了一個事務不會讀到另外一個並行事務已修改但未提交的數據,避免了「髒讀取」。該級別適用於大多數系統。
四、Read Uncommitted:保證了讀取過程當中不會讀取到非法數據。隔離級別在於處理多事務的併發問題。
咱們知道並行能夠提升數據庫的吞吐量和效率,可是並非全部的併發事務均可以併發運行,這須要查看數據庫教材的可串行化條件判斷了。
這裏就不闡述。
咱們首先說併發中可能發生的3中不討人喜歡的事情
1: Dirty reads--讀髒數據。也就是說,好比事務A的未提交(還依然緩存)的數據被事務B讀走,若是事務A失敗回滾,會致使事務B所讀取的的數據是錯誤的。
2: non-repeatable reads--數據不可重複讀。好比事務A中兩處讀取數據-total-的值。在第一讀的時候,total是100,而後事務B就把total的數據改爲 200,事務A再讀一次,結果就發現,total居然就變成200了,形成事務A數據混亂。
3: phantom reads--幻象讀數據,這個和non-repeatable reads類似,也是同一個事務中屢次讀不一致的問題。可是non-repeatable reads的不一致是由於他所要取的數據集被改變了(好比total的數據),可是phantom reads所要讀的數據的不一致卻不是他所要讀的數據集改變,而是他的條件數據集改變。好比Select account.id where account.name="ppgogo*",第一次讀去了6個符合條件的id,第二次讀取的時候,因爲事務b把一個賬號的名字由"dd"改爲"ppgogo1",結果取出來了7個數據。
| | Dirty reads | non-repeatable reads | phantom reads |
| Serializable | 不會 | 不會 | 不會 |
| REPEATABLE READ | 不會 | 不會 | 會 |
| READ COMMITTED | 不會 | 會 | 會 |
| Read Uncommitted | 會 | 會 | 會 |
3、readOnly
事務屬性中的readOnly標誌表示對應的事務應該被最優化爲只讀事務。
這是一個最優化提示。在一些狀況下,一些事務策略可以起到顯著的最優化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)時避免dirty checking(試圖「刷新」)。
4、Timeout
在事務屬性中還有定義「timeout」值的選項,指定事務超時爲幾秒。在JTA中,這將被簡單地傳遞到J2EE服務器的事務協調程序,並據此獲得相應的解釋
spring裏面事務的傳播屬性和事務隔離級別
1、Propagation (事務的傳播屬性)
Propagation : key屬性肯定代理應該給哪一個方法增長事務行爲。這樣的屬性最重要的部份是傳播行爲。有如下選項可供使用:PROPAGATION_REQUIRED--支持當前事務,若是當前沒有事務,就新建一個事務。這是最多見的選擇。
PROPAGATION_SUPPORTS--支持當前事務,若是當前沒有事務,就以非事務方式執行。
PROPAGATION_MANDATORY--支持當前事務,若是當前沒有事務,就拋出異常。
PROPAGATION_REQUIRES_NEW--新建事務,若是當前存在事務,把當前事務掛起。
PROPAGATION_NOT_SUPPORTED--以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。
PROPAGATION_NEVER--以非事務方式執行,若是當前存在事務,則拋出異常。
1: PROPAGATION_REQUIRED
加入當前正要執行的事務不在另一個事務裏,那麼就起一個新的事務
好比說,ServiceB.methodB的事務級別定義爲PROPAGATION_REQUIRED, 那麼因爲執行ServiceA.methodA的時候,
ServiceA.methodA已經起了事務,這時調用ServiceB.methodB,ServiceB.methodB看到本身已經運行在ServiceA.methodA
的事務內部,就再也不起新的事務。而假如ServiceA.methodA運行的時候發現本身沒有在事務中,他就會爲本身分配一個事務。
這樣,在ServiceA.methodA或者在ServiceB.methodB內的任何地方出現異常,事務都會被回滾。即便ServiceB.methodB的事務已經被
提交,可是ServiceA.methodA在接下來fail要回滾,ServiceB.methodB也要回滾
2: PROPAGATION_SUPPORTS
若是當前在事務中,即以事務的形式運行,若是當前再也不一個事務中,那麼就以非事務的形式運行
3: PROPAGATION_MANDATORY
必須在一個事務中運行。也就是說,他只能被一個父事務調用。不然,他就要拋出異常
4: PROPAGATION_REQUIRES_NEW
這個就比較繞口了。 好比咱們設計ServiceA.methodA的事務級別爲PROPAGATION_REQUIRED,ServiceB.methodB的事務級別爲PROPAGATION_REQUIRES_NEW,
那麼當執行到ServiceB.methodB的時候,ServiceA.methodA所在的事務就會掛起,ServiceB.methodB會起一個新的事務,等待ServiceB.methodB的事務完成之後,
他才繼續執行。他與PROPAGATION_REQUIRED 的事務區別在於事務的回滾程度了。由於ServiceB.methodB是新起一個事務,那麼就是存在
兩個不一樣的事務。若是ServiceB.methodB已經提交,那麼ServiceA.methodA失敗回滾,ServiceB.methodB是不會回滾的。若是ServiceB.methodB失敗回滾,
若是他拋出的異常被ServiceA.methodA捕獲,ServiceA.methodA事務仍然可能提交。
5: PROPAGATION_NOT_SUPPORTED
當前不支持事務。好比ServiceA.methodA的事務級別是PROPAGATION_REQUIRED ,而ServiceB.methodB的事務級別是PROPAGATION_NOT_SUPPORTED ,
那麼當執行到ServiceB.methodB時,ServiceA.methodA的事務掛起,而他以非事務的狀態運行完,再繼續ServiceA.methodA的事務。
6: PROPAGATION_NEVER
不能在事務中運行。假設ServiceA.methodA的事務級別是PROPAGATION_REQUIRED, 而ServiceB.methodB的事務級別是PROPAGATION_NEVER ,
那麼ServiceB.methodB就要拋出異常了。
7: PROPAGATION_NESTED
理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區別是,PROPAGATION_REQUIRES_NEW另起一個事務,將會與他的父事務相互獨立,
而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,若是父事務最後回滾,他也要回滾的。
而Nested事務的好處是他有一個savepoint。
ServiceA {
/**
*/
void methodA() {
try {
//savepoint
ServiceB.methodB(); //PROPAGATION_NESTED 級別
} catch (SomeException) {
// 執行其餘業務, 如 ServiceC.methodC();
}
}
}
也就是說ServiceB.methodB失敗回滾,那麼ServiceA.methodA也會回滾到savepoint點上,ServiceA.methodA能夠選擇另一個分支,好比
ServiceC.methodC,繼續執行,來嘗試完成本身的事務。
可是這個事務並無在EJB標準中定義。
2、Isolation Level(事務隔離等級):
一、Serializable:最嚴格的級別,事務串行執行,資源消耗最大;
二、REPEATABLE READ:保證了一個事務不會修改已經由另外一個事務讀取但未提交(回滾)的數據。避免了「髒讀取」和「不可重複讀取」的狀況,可是帶來了更多的性能損失。
三、READ COMMITTED:大多數主流數據庫的默認事務等級,保證了一個事務不會讀到另外一個並行事務已修改但未提交的數據,避免了「髒讀取」。該級別適用於大多數系統。
四、Read Uncommitted:保證了讀取過程當中不會讀取到非法數據。隔離級別在於處理多事務的併發問題。
咱們知道並行能夠提升數據庫的吞吐量和效率,可是並非全部的併發事務均可以併發運行,這須要查看數據庫教材的可串行化條件判斷了。
這裏就不闡述。
咱們首先說併發中可能發生的3中不討人喜歡的事情
1: Dirty reads--讀髒數據。也就是說,好比事務A的未提交(還依然緩存)的數據被事務B讀走,若是事務A失敗回滾,會致使事務B所讀取的的數據是錯誤的。
2: non-repeatable reads--數據不可重複讀。好比事務A中兩處讀取數據-total-的值。在第一讀的時候,total是100,而後事務B就把total的數據改爲 200,事務A再讀一次,結果就發現,total居然就變成200了,形成事務A數據混亂。
3: phantom reads--幻象讀數據,這個和non-repeatable reads類似,也是同一個事務中屢次讀不一致的問題。可是non-repeatable reads的不一致是由於他所要取的數據集被改變了(好比total的數據),可是phantom reads所要讀的數據的不一致卻不是他所要讀的數據集改變,而是他的條件數據集改變。好比Select account.id where account.name="ppgogo*",第一次讀去了6個符合條件的id,第二次讀取的時候,因爲事務b把一個賬號的名字由"dd"改爲"ppgogo1",結果取出來了7個數據。
Dirty reads non-repeatable reads phantom reads
Serializable 不會 不會 不會
REPEATABLE READ 不會 不會 會
READ COMMITTED 不會 會 會
Read Uncommitted 會 會 會
3、readOnly
事務屬性中的readOnly標誌表示對應的事務應該被最優化爲只讀事務。
這是一個最優化提示。在一些狀況下,一些事務策略可以起到顯著的最優化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)時避免dirty checking(試圖「刷新」)。
4、Timeout
在事務屬性中還有定義「timeout」值的選項,指定事務超時爲幾秒。在JTA中,這將被簡單地傳遞到J2EE服務器的事務協調程序,並據此獲得相應的解釋
20110112
數據庫提供了四種事務隔離級別, 不一樣的隔離級別採用不一樣的鎖類開來實現.
在四種隔離級別中, Serializable的級別最高, Read Uncommited級別最低.
大多數數據庫的默認隔離級別爲: Read Commited,如Sql Server , Oracle.
少數數據庫默認的隔離級別爲Repeatable Read, 如MySQL InnoDB存儲引擎
即便是最低的級別,也不會出現 第一類 丟失 更新問題 .
1. 髒讀(事務沒提交,提早讀取) :髒讀就是指當一個事務正在訪問數據,而且對數據進行了修改,而這種修改尚未提交到數據庫中,這時,另一個事務也訪問這個數據,而後使用了這個數據。
2. 不可重複讀(兩次讀的不一致) :是指在一個事務內,屢次讀同一數據。在這個事務尚未結束時,另一個事務也訪問該同一數據。那麼,在第一個事務中的兩次讀數據之間,因爲第二個事務的修改,那麼第一個事務兩次讀到的的數據多是不同的。這樣就發生了在一個事務內兩次讀到的數據是不同的,所以稱爲是不可重複讀。例如,一個編輯人員兩次讀取同一文檔,但在兩次讀取之間,做者重寫了該文檔。當編輯人員第二次讀取文檔時,文檔已更改。原始讀取不可重複。若是隻有在做者所有完成編寫後編輯人員才能夠讀取文檔,則能夠避免該問題。
3. 幻讀 : 是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的所有數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那麼,之後就會發生操做第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺同樣。例如,一個編輯人員更改做者提交的文檔,但當生產部門將其更改內容合併到該文檔的主複本時,發現做者已將未編輯的新材料添加到該文檔中。若是在編輯人員和生產部門完成對原始文檔的處理以前,任何人都不能將新材料添加到文檔中,則能夠避免該問題。
4. 第一類更新丟失(回滾丟失) :
當2個事務更新相同的數據源,若是第一個事務被提交,而另一個事務卻被撤銷,那麼會連同第一個事務所作的跟新也被撤銷。也就是說第一個事務作的跟新丟失了。
5. 第二類更新丟失(覆蓋丟失) :
第二類更新丟失實在實際應用中常常遇到的併發問題,他和不可重複讀本質上是同一類併發問題,一般他被看作不可重複讀的特例:當2個或這個多個事務查詢一樣的記錄而後各自基於最初的查詢結果更新該行時,會形成第二類丟失更新。由於每一個事務都不知道不知道其餘事務的存在,最後一個事務對記錄作的修改將覆蓋其餘事務對該記錄作的已提交的跟新...
補充 : 基於元數據的 Spring 聲明性事務 :
Isolation 屬性一共支持五種事務設置,具體介紹以下:
l DEFAULT 使用數據庫設置的隔離級別 ( 默認 ) ,由 DBA 默認的設置來決定隔離級別 .
l READ_UNCOMMITTED 會出現髒讀、不可重複讀、幻讀 ( 隔離級別最低,併發性能高 )
l READ_COMMITTED 會出現不可重複讀、幻讀問題(鎖定正在讀取的行)
l REPEATABLE_READ 會出幻讀(鎖定所讀取的全部行)
l SERIALIZABLE 保證全部的狀況不會發生(鎖表)
不可重複讀的重點是修改 :
一樣的條件 , 你讀取過的數據 , 再次讀取出來發現值不同了
幻讀的重點在於新增或者刪除
一樣的條件 , 第 1 次和第 2 次讀出來的記錄數不同!