spring 事務管理
事務
事務是應用程序中一系列嚴密的操作,所有操作必須成功完成,否則在每個操作中所作的所有更改都會被撤消。也就是事務具有原子性,一個事務中的一系列的操作要么全部成功,要么一個都不做。 事務的結束有兩種,當事務中的所以步驟全部成功執(zhí)行時,事務提交。如果其中一個步驟失敗,將發(fā)生回滾操作,撤消撤消之前到事務開始時的所以操作。就像從小父母教育我們要有始有終,不能半途而廢。
事務的ACID
事務具有四個特征:原子性( Atomicity )、一致性( Consistency )、隔離性( Isolation )和持續(xù)性( Durability )。這四個特性簡稱為 ACID 特性。
1 、原子性
事務是數(shù)據(jù)庫的邏輯工作單位,事務中包含的各操作要么都做,要么都不做
2 、一致性
事務執(zhí)行的結果必須是使數(shù)據(jù)庫從一個一致性狀態(tài)變到另一個一致性狀態(tài)。因此當數(shù)據(jù)庫只包含成功事務提交的結果時,就說數(shù)據(jù)庫處于一致性狀態(tài)。如果數(shù)據(jù)庫系統(tǒng) 運行中發(fā)生故障,有些事務尚未完成就被迫中斷,這些未完成事務對數(shù)據(jù)庫所做的修改有一部分已寫入物理數(shù)據(jù)庫,這時數(shù)據(jù)庫就處于一種不正確的狀態(tài),或者說是不一致的狀態(tài)。
比如轉賬:A轉給B5000塊,A的賬號扣了錢,但是B的賬號沒有增加。
3 、隔離性
一個事務的執(zhí)行不能其它事務干擾。即一個事務內部的操作及使用的數(shù)據(jù)對其它并發(fā)事務是隔離的,并發(fā)執(zhí)行的各個事務之間不能互相干擾。比如我們在updata的那一剎那,有可能別人提交了一個delete對于同一個數(shù)據(jù)進行操作。可以想象這樣會出麻煩,必須加以控制,讓他們順序的執(zhí)行,鎖進行控制。保證數(shù)據(jù)庫操作之間是隔離的,沒有干擾的。隔離的級別越高,那么并發(fā)性,吞吐量肯定會收到影響。數(shù)據(jù)庫專家們制定了數(shù)據(jù)庫隔離的規(guī)范,防止臟讀,不可重復讀..
4 、持續(xù)性
也稱永久性,指一個事務一旦提交,它對數(shù)據(jù)庫中的數(shù)據(jù)的改變就應該是永久性的。接下來的其它操作或故障不應該對其執(zhí)行結果有任何影響。
事務隔離面臨的影響
臟讀:事務A讀取了事務B未提交的數(shù)據(jù)
不可重復讀:事務A讀取了事務B已提交更改的數(shù)據(jù)。
幻讀:事務A讀取了事務B已提交新增的數(shù)據(jù)。
事務隔離性的定義:Isolation: Concurrently executing transactions see the stored information as if they were running serially (one after another)
事務的隔離級別從低到高有:
Read Uncommitted:最低的隔離級別,什么都不需要做,一個事務可以讀到另一個事務未提交的結果。所有的并發(fā)事務問題都會發(fā)生。
Read Committed:只有在事務提交后,其更新結果才會被其他事務看見。可以解決臟讀問題。
Repeated Read:在一個事務中,對于同一份數(shù)據(jù)的讀取結果總是相同的,無論是否有其他事務對這份數(shù)據(jù)進行操作,以及這個事務是否提交??梢越鉀Q臟讀、不可重復讀。
Serialization:事務串行化執(zhí)行,隔離級別最高,犧牲了系統(tǒng)的并發(fā)性。可以解決并發(fā)事務的所有問題。 通常,在工程實踐中,為了性能的考慮會對隔離性進行折中。
考慮到實踐,為了性能,數(shù)據(jù)庫廠商做出了這方面的妥協(xié),讓使用者可以選擇隔離的級別。不同的隔離級別可以解決不同階段的問題,是層層遞進,逐漸增強的關系。
隔離性為了解決的問題主要有三個(將事務的隔離級別和問題聯(lián)系在一起理解):
臟讀(Drity Read):事務A修改了一個數(shù)據(jù),但未提交,事務B讀到了事務A未提交的更新結果,如果事務A提交失敗,事務B讀到的就是臟數(shù)據(jù)。Read Committed可以解決臟讀問題,但仍存在以下兩種問題。
不可重復讀(Non-repeatable read): 在同一個事務中,對于同一份數(shù)據(jù)讀取到的結果不一致。比如,事務B在事務A提交前讀到的結果,和提交后讀到的結果可能不同。不可重復讀出現(xiàn)的原因就是事務并發(fā)修改記錄,要避免這種情況,最簡單的方法就是對要修改的記錄加鎖,這導致鎖競爭加劇,影響性能。Repeated Read可以解決不可重復讀問題和臟讀問題,但仍無法解決下面的問題。
幻讀(Phantom Read): 在同一個事務中,同一個查詢多次返回的結果不一致。事務A新增了一條記錄,事務B在事務A提交前后各執(zhí)行了一次查詢操作,發(fā)現(xiàn)后一次比前一次多了一條記錄?;米x僅指由于并發(fā)事務增加記錄導致的問題,這個不能像不可重復讀通過記錄加鎖解決,因為對于新增的記錄根本無法加鎖。需要將事務串行化,才能避免幻讀。Serialization解決了以上所有問題,但是性能效率較低。通常來說,事務隔離級別越低,所需持有鎖的時間也就越短,并發(fā)性能也就越好。
不可重復讀的例子:
不可重復讀的重點是修改:同樣的條件, 你讀取過的數(shù)據(jù), 再次讀取出來發(fā)現(xiàn)值不一樣了
在事務1中,Mary 讀取了自己的工資為1000,操作并沒有完成
con1 = getConnection();
select salary from employee empId = "Mary" ;
在事務2中,這時財務人員修改了Mary的工資為2000,并提交了事務.
con2 = getConnection();
update employee set salary = 2000 ;
con2.commit();
在事務1中,Mary 再次讀取自己的工資時,工資變?yōu)榱?000
select salary from employee empId = "Mary" ;
在一個事務中前后兩次讀取的結果并不致,導致了不可重復讀。
幻讀例子:
幻讀:幻讀的重點在于新增或者刪除 同樣的條件, 第1次和第2次讀出來的記錄數(shù)不一樣
目前工資為1000的員工有10人。
事務1,讀取所有工資為1000的員工。
con1 = getConnection();
Select * from employee where salary = 1000 ;
共讀取10條記錄
這時另一個事務向employee表插入了一條員工記錄,工資也為1000
con2 = getConnection();
Insert into employee(empId,salary) values( "Lili" , 1000 );
con2.commit();
事務1再次讀取所有工資為1000的員工
select * from employee where salary = 1000 ;
共讀取到了11條記錄,這就產生了幻像讀。
spring 事務的隔離級別(方法間調用)
ISOLATION_DEFAULT:數(shù)據(jù)庫默認
ISOLATION_COMMITTED:允許讀取其他并發(fā)事務已經(jīng)提交的更新(防此臟讀)
ISOLATION—READ_UNCOMMITTED允許讀取其他并發(fā)事務還未提交的更新,會導致事務之間的3個缺陷發(fā)生,這是速度最快的一個隔離級別,但同時它的隔離級別也是最低
ISOLATION_SERIALIZABLE 這是最高的隔離級別,它可以防此臟讀,不可重復讀和 幻讀等問題,但因其侵占式的數(shù)據(jù)記錄完全鎖定,導致它影響事務的性能,成為隔離級別中最展慢的一個。 注意:并不是所有的資源管理器都支持所有的隔離級別,可針對不同的資源管理使用以上的隔離級別.
事務的傳播行為
PROPAGATION_MANDATORY: (強制性,傳播)
規(guī)定了方法必須在事務中運行,否則會拋出異常
PROPAGATION_NEVER(調用的方法不能有事務)
使當前方法永遠不在事務中運行,否則拋出異常
PROPAGATION-NOT_SUPPORTED
定義為當前事務不支持的方法,在該方法運行期間正在運行的事務會被暫停
PROPAGATION_REQUIRED(夠用)
規(guī)定當前的方法必須在事務中,如果沒有事務就創(chuàng)建一個新事務,一個新事務和方法一同開始,隨著方法的返回或拋出異常而終止
PROPAGATION-REQUIRED_NEW
當前方法必須創(chuàng)建新的事務來運行,如果現(xiàn)存的事務正在運行就暫停它
PROPAGATION_SUPPORTS
規(guī)定當前方法支持當前事務處理,但如果沒有事務在運行就使用非事務方法執(zhí)行
事務的只讀屬性
在對數(shù)據(jù)庫的操作中,查詢是使用最頻繁的操作,每次執(zhí)行查詢時都要從數(shù)據(jù)庫中重新讀取數(shù)據(jù),有時多次讀取的數(shù)據(jù)都是相同的,這樣的數(shù)據(jù)操作不僅浪費了系統(tǒng)資源,還影響了系統(tǒng)速度。對訪問量大的程序來說,節(jié)省這部分資源可以大大提升系統(tǒng)速度。如果將事務聲明為只讀的,那么數(shù)據(jù)庫可以根據(jù)事務的特性優(yōu)化事務的讀取操作。事務的只讀屬性需要配合事務的傳播行為共同設置.
事務超時屬性
這個屬性和事務的只讀屬性一樣需要搭配事務的傳播行為共同設置,它設置了事務的超時時間,事務本身可能會因某種原因很長沒有回應,在這期間事務可能鎖定了數(shù)據(jù)庫的表格,這樣會出現(xiàn)嚴重的性能問題。通過設置事務的超時時間,從開始執(zhí)行事務起,在規(guī)定的超時時間內如果沒有事務就將它回滾。
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
String value() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default -1;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
spring 事務管理器
都實現(xiàn)了PlatformTransactionManager接口
DataSourceTransactionManager JDBC事務管理器
HibernateTransactionManager Hibernate事務管理器
<!-- 配置JDBC事務管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<!-- 配置Hibernate事務管理器 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
啟動注解,@Transactional
<tx:annotation-driven transaction-manager="transactionManager"/>
使用AOP的方式實現(xiàn)事務的配置
<tx:advice id="TestAdvice" transaction-manager="transactionManager">
<!--配置事務傳播性,隔離級別以及超時回滾等問題 -->
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="*" rollback-for="java.lang.Exception" timeout="-1" isolation="READ_COMMITTED" read-only="true" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<!--配置事務切點 -->
<aop:pointcut id="services"
expression="execution(* com.website.service.*.*(..))" />
<aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />
</aop:config>
本文摘自 :https://blog.51cto.com/u