spring事物的七種事物傳播屬性行為及五種隔離級別
首先,說說什麼事務(Transaction)。
事務,就是一組操作數據庫的動作集合。事務是現代數據庫理論中的核心概念之一。如果一組處理步驟或者全部發生或者一步也不執行,我們稱該組處理步驟為一個事務。當所有的步驟像一個操作一樣被完整地執行,我們稱該事務被提交。由於其中的一部分或多步執行失敗,導致沒有步驟被提交,則事務必須回滾到最初的係統狀態。
其中spring七個事物傳播屬性:
PROPAGATION_REQUIRED -- 支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
PROPAGATION_SUPPORTS -- 支持當前事務,如果當前沒有事務,就以非事務方式執行。
PROPAGATION_MANDATORY -- 支持當前事務,如果當前沒有事務,就拋出異常。
PROPAGATION_REQUIRES_NEW -- 新建事務,如果當前存在事務,把當前事務掛起。
PROPAGATION_NOT_SUPPORTED -- 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
PROPAGATION_NEVER -- 以非事務方式執行,如果當前存在事務,則拋出異常。
PROPAGATION_NESTED -- 如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,
則進行與PROPAGATION_REQUIRED類似的操作。
五個隔離級別:
ISOLATION_DEFAULT 這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別.
另外四個與JDBC的隔離級別相對應;
ISOLATION_READ_UNCOMMITTED 這是事務最低的隔離級別,它充許別外一個事務可以看到這個事務未提交的數據。
這種隔離級別會產生髒讀,不可重複讀和幻像讀。
ISOLATION_READ_COMMITTED 保證一個事務修改的數據提交後才能被另外一個事務讀取。另外一個事務不能讀取
該事務未提交的數據。這種事務隔離級別可以避免髒讀出現,但是可能會出現不可重複讀和幻像讀。
ISOLATION_REPEATABLE_READ 這種事務隔離級別可以防止髒讀,不可重複讀。但是可能出現幻像讀。它除了保證
一個事務不能讀取另一個事務未提交的數據外,還保證了避免下麵的情況產生(不可重複讀)。
ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執行。除了防止髒讀,
不可重複讀外,還避免了幻像讀。
關鍵詞:
1)幻讀:事務1讀取記錄時事務2增加了記錄並提交,事務1再次讀取時可以看到事務2新增的記錄;
2)不可重複讀取:事務1讀取記錄時,事務2更新了記錄並提交,事務1再次讀取時可以看到事務2修改後的記錄;
3)髒讀:事務1更新了記錄,但沒有提交,事務2讀取了更新後的行,然後事務T1回滾,現在T2讀取無效。
Spring事務配置的五種方式
前段時間對Spring的事務配置做了比較深入的研究,在此之間對Spring的事務配置雖說也配置過,但是一直沒有一個清楚的認識。通過這次的學習發覺Spring的事務配置隻要把思路理清,還是比較好掌握的。
總結如下:
Spring配置文件中關於事務配置總是由三個組成部分,分別是DataSource、TransactionManager和代理機製這三部分,無論哪種配置方式,一般變化的隻是代理機製這部分。
DataSource、TransactionManager這兩部分隻是會根據數據訪問方式有所變化,比如使用Hibernate進行數據訪問時,DataSource實際為SessionFactory,TransactionManager的實現為HibernateTransactionManager。
具體如下圖:
根據代理機製的不同,總結了五種Spring事務的配置方式,配置文件如下:
第一種方式:每個Bean都有一個代理
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:aop="https://www.springframework.org/schema/aop"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-2.5.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-2.5.xsd
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean
>
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定義事務管理器(聲明式的事務) -->
<bean
>
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!--配置DAO -->
<bean >
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean
>
<!--配置事務管理器 -->
<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共享一個代理基類
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:aop="https://www.springframework.org/schema/aop"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-2.5.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-2.5.xsd
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean
>
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!--定義事務管理器(聲明式的事務)-->
<bean >
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean
lazy-init="true" abstract="true">
<!-- 配置事務管理器 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事務屬性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 配置DAO -->
<bean >
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean parent="transactionBase" >
<property name="target" ref="userDaoTarget" />
</bean>
</beans>
第三種方式:使用攔截器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:aop="https://www.springframework.org/schema/aop"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-2.5.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-2.5.xsd
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean
>
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!--定義事務管理器(聲明式的事務)-->
<bean
>
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean
>
<property name="transactionManager" ref="transactionManager" />
<!--配置事務屬性-->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean >
<property name="beanNames">
<list>
<value>*Dao</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
<!-- 配置DAO-->
<bean >
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
第四種方式:使用tx標簽配置的攔截器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:aop="https://www.springframework.org/schema/aop"
xmlns:tx="https://www.springframework.org/schema/tx"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-2.5.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-2.5.xsd
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-2.5.xsd
https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package="com.bluesky" />
<bean
>
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!--定義事務管理器(聲明式的事務)-->
<bean
>
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut
expression="execution( com.bluesky.spring.dao..*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="interceptorPointCuts" />
</aop:config>
</beans>
第五種方式:全注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:aop="https://www.springframework.org/schema/aop"
xmlns:tx="https://www.springframework.org/schema/tx"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-2.5.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-2.5.xsd
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-2.5.xsd
https://www.springframework.org/schema/tx https://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
>
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
</bean>
<!-- 定義事務管理器(聲明式的事務) -->
<bean
>
<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裏麵事務的傳播屬性和事務隔離級別
一、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 {
/**
-
事務屬性配置為 PROPAGATION_REQUIRED
*/
void methodA() {
try {
//savepoint
ServiceB.methodB(); //PROPAGATION_NESTED 級別
} catch (SomeException) {
// 執行其他業務, 如 ServiceC.methodC();
}
}
}
也就是說ServiceB.methodB失敗回滾,那麼ServiceA.methodA也會回滾到savepoint點上,ServiceA.methodA可以選擇另外一個分支,比如
ServiceC.methodC,繼續執行,來嚐試完成自己的事務。
但是這個事務並沒有在EJB標準中定義。
二、Isolation Level(事務隔離等級):
1、Serializable:最嚴格的級別,事務串行執行,資源消耗最大;
2、REPEATABLE READ:保證了一個事務不會修改已經由另一個事務讀取但未提交(回滾)的數據。避免了“髒讀取”和“不可重複讀取”的情況,但是帶來了更多的性能損失。
3、READ COMMITTED:大多數主流數據庫的默認事務等級,保證了一個事務不會讀到另一個並行事務已修改但未提交的數據,避免了“髒讀取”。該級別適用於大多數係統。
4、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 會 會 會
三、readOnly
事務屬性中的readOnly標誌表示對應的事務應該被最優化為隻讀事務。
這是一個最優化提示。在一些情況下,一些事務策略能夠起到顯著的最優化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)時避免dirty checking(試圖“刷新”)。
四、Timeout
在事務屬性中還有定義“timeout”值的選項,指定事務超時為幾秒。在JTA中,這將被簡單地傳遞到J2EE服務器的事務協調程序,並據此得到相應的解釋
spring裏麵事務的傳播屬性和事務隔離級別
一、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 {
/**
-
事務屬性配置為 PROPAGATION_REQUIRED
*/
void methodA() {
try {
//savepoint
ServiceB.methodB(); //PROPAGATION_NESTED 級別
} catch (SomeException) {
// 執行其他業務, 如 ServiceC.methodC();
}
}
}
也就是說ServiceB.methodB失敗回滾,那麼ServiceA.methodA也會回滾到savepoint點上,ServiceA.methodA可以選擇另外一個分支,比如
ServiceC.methodC,繼續執行,來嚐試完成自己的事務。
但是這個事務並沒有在EJB標準中定義。
二、Isolation Level(事務隔離等級):
1、Serializable:最嚴格的級別,事務串行執行,資源消耗最大;
2、REPEATABLE READ:保證了一個事務不會修改已經由另一個事務讀取但未提交(回滾)的數據。避免了“髒讀取”和“不可重複讀取”的情況,但是帶來了更多的性能損失。
3、READ COMMITTED:大多數主流數據庫的默認事務等級,保證了一個事務不會讀到另一個並行事務已修改但未提交的數據,避免了“髒讀取”。該級別適用於大多數係統。
4、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 會 會 會
三、readOnly
事務屬性中的readOnly標誌表示對應的事務應該被最優化為隻讀事務。
這是一個最優化提示。在一些情況下,一些事務策略能夠起到顯著的最優化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)時避免dirty checking(試圖“刷新”)。
四、Timeout
在事務屬性中還有定義“timeout”值的選項,指定事務超時為幾秒。在JTA中,這將被簡單地傳遞到J2EE服務器的事務協調程序,並據此得到相應的解釋
20110112
數據庫提供了四種事務隔離級別, 不同的隔離級別采用不同的鎖類開來實現.
在四種隔離級別中, Serializable的級別最高, Read Uncommited級別最低.
大多數數據庫的默認隔離級別為: Read Commited,如Sql Server , Oracle.
少數數據庫默認的隔離級別為Repeatable Read, 如MySQL InnoDB存儲引擎
即使是最低的級別,也不會出現 第一類 丟失 更新問題 .
髒讀(事務沒提交,提前讀取) :髒讀就是指當一個事務正在訪問數據,並且對數據進行了修改,而這種修改還沒有提交到數據庫中,這時,另外一個事務也訪問這個數據,然後使用了這個數據。
不可重複讀(兩次讀的不一致) :是指在一個事務內,多次讀同一數據。在這個事務還沒有結束時,另外一個事務也訪問該同一數據。那麼,在第一個事務中的兩次讀數據之間,由於第二個事務的修改,那麼第一個事務兩次讀到的的數據可能是不一樣的。這樣就發生了在一個事務內兩次讀到的數據是不一樣的,因此稱為是不可重複讀。例如,一個編輯人員兩次讀取同一文檔,但在兩次讀取之間,作者重寫了該文檔。當編輯人員第二次讀取文檔時,文檔已更改。原始讀取不可重複。如果隻有在作者全部完成編寫後編輯人員才可以讀取文檔,則可以避免該問題。
幻讀 : 是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那麼,以後就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺一樣。例如,一個編輯人員更改作者提交的文檔,但當生產部門將其更改內容合並到該文檔的主複本時,發現作者已將未編輯的新材料添加到該文檔中。如果在編輯人員和生產部門完成對原始文檔的處理之前,任何人都不能將新材料添加到文檔中,則可以避免該問題。
第一類更新丟失(回滾丟失) :
當2個事務更新相同的數據源,如果第一個事務被提交,而另外一個事務卻被撤銷,那麼會連同第一個事務所做的跟新也被撤銷。也就是說第一個事務做的跟新丟失了。第二類更新丟失(覆蓋丟失) :
第二類更新丟失實在實際應用中經常遇到的並發問題,他和不可重複讀本質上是同一類並發問題,通常他被看做不可重複讀的特例:當2個或這個多個事務查詢同樣的記錄然後各自基於最初的查詢結果更新該行時,會造成第二類丟失更新。因為每個事務都不知道不知道其他事務的存在,最後一個事務對記錄做的修改將覆蓋其他事務對該記錄做的已提交的跟新...
補充 : 基於元數據的 Spring 聲明性事務 :
Isolation 屬性一共支持五種事務設置,具體介紹如下:
l DEFAULT 使用數據庫設置的隔離級別 ( 默認 ) ,由 DBA 默認的設置來決定隔離級別 .
l READ_UNCOMMITTED 會出現髒讀、不可重複讀、幻讀 ( 隔離級別最低,並發性能高 )
l READ_COMMITTED 會出現不可重複讀、幻讀問題(鎖定正在讀取的行)
l REPEATABLE_READ 會出幻讀(鎖定所讀取的所有行)
l SERIALIZABLE 保證所有的情況不會發生(鎖表)
不可重複讀的重點是修改 :
同樣的條件 , 你讀取過的數據 , 再次讀取出來發現值不一樣了
幻讀的重點在於新增或者刪除
同樣的條件 , 第 1 次和第 2 次讀出來的記錄數不一樣
轉自:https://www.cnblogs.com/yuanfy008/p/4174340.html
轉自:https://blog.csdn.net/it_man/article/details/5074371
最後更新:2017-11-02 11:34:09