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