Spring事務(wù)管理(詳解+實(shí)例)_第1頁(yè)
Spring事務(wù)管理(詳解+實(shí)例)_第2頁(yè)
Spring事務(wù)管理(詳解+實(shí)例)_第3頁(yè)
Spring事務(wù)管理(詳解+實(shí)例)_第4頁(yè)
Spring事務(wù)管理(詳解+實(shí)例)_第5頁(yè)
已閱讀5頁(yè),還剩35頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

參考的文章如下:Spring事務(wù)機(jī)制詳解Spring事務(wù)配置的五種方式Spring中的事務(wù)管理實(shí)例詳解1初步理解理解事務(wù)之前,先講一個(gè)你日常生活中最常干的事:取錢(qián)。

比方你去ATM機(jī)取1000塊錢(qián),大體有兩個(gè)步驟:首先輸入密碼金額,銀行卡扣掉1000元錢(qián);然后ATM出1000元錢(qián)。這兩個(gè)步驟必須是要么都執(zhí)行要么都不執(zhí)行。如果銀行卡扣除了1000塊但是ATM出錢(qián)失敗的話(huà),你將會(huì)損失1000元;如果銀行卡扣錢(qián)失敗但是ATM卻出了1000塊,那么銀行將損失1000元。所以,如果一個(gè)步驟成功另一個(gè)步驟失敗對(duì)雙方都不是好事,如果不管哪一個(gè)步驟失敗了以后,整個(gè)取錢(qián)過(guò)程都能回滾,也就是完全取消所有操作的話(huà),這對(duì)雙方都是極好的。

事務(wù)就是用來(lái)解決類(lèi)似問(wèn)題的。事務(wù)是一系列的動(dòng)作,它們綜合在一起才是一個(gè)完整的工作單元,這些動(dòng)作必須全部完成,如果有一個(gè)失敗的話(huà),那么事務(wù)就會(huì)回滾到最開(kāi)始的狀態(tài),仿佛什么都沒(méi)發(fā)生過(guò)一樣。

在企業(yè)級(jí)應(yīng)用程序開(kāi)發(fā)中,事務(wù)管理必不可少的技術(shù),用來(lái)確保數(shù)據(jù)的完整性和一致性。

事務(wù)有四個(gè)特性:ACID原子性〔Atomicity〕:事務(wù)是一個(gè)原子操作,由一系列動(dòng)作組成。事務(wù)的原子性確保動(dòng)作要么全部完成,要么完全不起作用。一致性〔Consistency〕:一旦事務(wù)完成〔不管成功還是失敗〕,系統(tǒng)必須確保它所建模的業(yè)務(wù)處于一致的狀態(tài),而不會(huì)是局部完成局部失敗。在現(xiàn)實(shí)中的數(shù)據(jù)不應(yīng)該被破壞。隔離性〔Isolation〕:可能有許多事務(wù)會(huì)同時(shí)處理相同的數(shù)據(jù),因此每個(gè)事務(wù)都應(yīng)該與其他事務(wù)隔離開(kāi)來(lái),防止數(shù)據(jù)損壞。持久性〔Durability〕:一旦事務(wù)完成,無(wú)論發(fā)生什么系統(tǒng)錯(cuò)誤,它的結(jié)果都不應(yīng)該受到影響,這樣就能從任何系統(tǒng)崩潰中恢復(fù)過(guò)來(lái)。通常情況下,事務(wù)的結(jié)果被寫(xiě)到持久化存儲(chǔ)器中。2核心接口Spring事務(wù)管理的實(shí)現(xiàn)有許多細(xì)節(jié),如果對(duì)整個(gè)接口框架有個(gè)大體了解會(huì)非常有利于我們理解事務(wù),下面通過(guò)講解Spring的事務(wù)接口來(lái)了解Spring實(shí)現(xiàn)事務(wù)的具體策略。

Spring事務(wù)管理涉及的接口的聯(lián)系如下:2.1事務(wù)管理器Spring并不直接管理事務(wù),而是提供了多種事務(wù)管理器,他們將事務(wù)管理的職責(zé)委托給Hibernate或者JTA等持久化機(jī)制所提供的相關(guān)平臺(tái)框架的事務(wù)來(lái)實(shí)現(xiàn)。

Spring事務(wù)管理器的接口是,通過(guò)這個(gè)接口,Spring為各個(gè)平臺(tái)如JDBC、Hibernate等都提供了對(duì)應(yīng)的事務(wù)管理器,但是具體的實(shí)現(xiàn)就是各個(gè)平臺(tái)自己的事情了。此接口的內(nèi)容如下:PublicinterfacePlatformTransactionManager()...{//由TransactionDefinition得到TransactionStatus對(duì)象TransactionStatusgetTransaction(TransactionDefinitiondefinition)throwsTransactionException;//提交Voidcommit(TransactionStatusstatus)throwsTransactionException;//回滾Voidrollback(TransactionStatusstatus)throwsTransactionException;}從這里可知具體的具體的事務(wù)管理機(jī)制對(duì)Spring來(lái)說(shuō)是透明的,它并不關(guān)心那些,那些是對(duì)應(yīng)各個(gè)平臺(tái)需要關(guān)心的,所以Spring事務(wù)管理的一個(gè)優(yōu)點(diǎn)就是為不同的事務(wù)API提供一致的編程模型,如JTA、JDBC、Hibernate、JPA。下面分別介紹各個(gè)平臺(tái)框架實(shí)現(xiàn)事務(wù)管理的機(jī)制。2.1.1JDBC事務(wù)如果應(yīng)用程序中直接使用JDBC來(lái)進(jìn)行持久化,DataSourceTransactionManager會(huì)為你處理事務(wù)邊界。為了使用DataSourceTransactionManager,你需要使用如下的XML將其裝配到應(yīng)用程序的上下文定義中:<beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><propertyname="dataSource"ref="dataSource"/></bean>實(shí)際上,DataSourceTransactionManager是通過(guò)調(diào)用來(lái)管理事務(wù),而后者是通過(guò)DataSource獲取到的。通過(guò)調(diào)用連接的commit()方法來(lái)提交事務(wù),同樣,事務(wù)失敗那么通過(guò)調(diào)用rollback()方法進(jìn)行回滾。2.1.2Hibernate事務(wù)如果應(yīng)用程序的持久化是通過(guò)Hibernate實(shí)習(xí)的,那么你需要使用HibernateTransactionManager。對(duì)于Hibernate3,需要在Spring上下文定義中添加如下的<bean>聲明:<beanid="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><propertyname="sessionFactory"ref="sessionFactory"/></bean>sessionFactory屬性需要裝配一個(gè)Hibernate的session工廠(chǎng),HibernateTransactionManager的實(shí)現(xiàn)細(xì)節(jié)是它將事務(wù)管理的職責(zé)委托給對(duì)象,而后者是從HibernateSession中獲取到的。當(dāng)事務(wù)成功完成時(shí),HibernateTransactionManager將會(huì)調(diào)用Transaction對(duì)象的commit()方法,反之,將會(huì)調(diào)用rollback()方法。2.1.3Java持久化API事務(wù)〔JPA〕Hibernate多年來(lái)一直是事實(shí)上的Java持久化標(biāo)準(zhǔn),但是現(xiàn)在Java持久化API作為真正的Java持久化標(biāo)準(zhǔn)進(jìn)入大家的視野。如果你方案使用JPA的話(huà),那你需要使用Spring的JpaTransactionManager來(lái)處理事務(wù)。你需要在Spring中這樣配置JpaTransactionManager:<beanid="transactionManager"class=""><propertyname="sessionFactory"ref="sessionFactory"/></bean>JpaTransactionManager只需要裝配一個(gè)JPA實(shí)體管理工廠(chǎng)〔接口的任意實(shí)現(xiàn)〕。JpaTransactionManager將與由工廠(chǎng)所產(chǎn)生的JPAEntityManager合作來(lái)構(gòu)建事務(wù)。2.1.4Java原生API事務(wù)如果你沒(méi)有使用以上所述的事務(wù)管理,或者是跨越了多個(gè)事務(wù)管理源〔比方兩個(gè)或者是多個(gè)不同的數(shù)據(jù)源〕,你就需要使用JtaTransactionManager:<beanid="transactionManager"class="org.springframework.transaction.jta.JtaTransactionManager"><propertyname="transactionManagerName"value="java:/TransactionManager"/></bean>JtaTransactionManager將事務(wù)管理的責(zé)任委托給和對(duì)象,其中事務(wù)成功完成通過(guò)UserTransactionmit()方法提交,事務(wù)失敗通過(guò)UserTransaction.rollback()方法回滾。2.2根本領(lǐng)務(wù)屬性的定義上面講到的事務(wù)管理器接口PlatformTransactionManager通過(guò)getTransaction(TransactionDefinitiondefinition)方法來(lái)得到事務(wù),這個(gè)方法里面的參數(shù)是TransactionDefinition類(lèi),這個(gè)類(lèi)就定義了一些根本的事務(wù)屬性。

那么什么是事務(wù)屬性呢?事務(wù)屬性可以理解成事務(wù)的一些根本配置,描述了事務(wù)策略如何應(yīng)用到方法上。事務(wù)屬性包含了5個(gè)方面,如下圖:而TransactionDefinition接口內(nèi)容如下:publicinterfaceTransactionDefinition{intgetPropagationBehavior();//返回事務(wù)的傳播行為intgetIsolationLevel();//返回事務(wù)的隔離級(jí)別,事務(wù)管理器根據(jù)它來(lái)控制另外一個(gè)事務(wù)可以看到本領(lǐng)務(wù)內(nèi)的哪些數(shù)據(jù)intgetTimeout();//返回事務(wù)必須在多少秒內(nèi)完成booleanisReadOnly();//事務(wù)是否只讀,事務(wù)管理器能夠根據(jù)這個(gè)返回值進(jìn)行優(yōu)化,確保事務(wù)是只讀的}我們可以發(fā)現(xiàn)TransactionDefinition正好用來(lái)定義事務(wù)屬性,下面詳細(xì)介紹一下各個(gè)事務(wù)屬性。2.2.1傳播行為事務(wù)的第一個(gè)方面是傳播行為〔propagationbehavior〕。當(dāng)事務(wù)方法被另一個(gè)事務(wù)方法調(diào)用時(shí),必須指定事務(wù)應(yīng)該如何傳播。例如:方法可能繼續(xù)在現(xiàn)有事務(wù)中運(yùn)行,也可能開(kāi)啟一個(gè)新事務(wù),并在自己的事務(wù)中運(yùn)行。Spring定義了七種傳播行為:傳播行為含義PROPAGATION_REQUIRED表示當(dāng)前方法必須運(yùn)行在事務(wù)中。如果當(dāng)前事務(wù)存在,方法將會(huì)在該事務(wù)中運(yùn)行。否那么,會(huì)啟動(dòng)一個(gè)新的事務(wù)PROPAGATION_SUPPORTS表示當(dāng)前方法不需要事務(wù)上下文,但是如果存在當(dāng)前事務(wù)的話(huà),那么該方法會(huì)在這個(gè)事務(wù)中運(yùn)行PROPAGATION_MANDATORY表示該方法必須在事務(wù)中運(yùn)行,如果當(dāng)前事務(wù)不存在,那么會(huì)拋出一個(gè)異常PROPAGATION_REQUIRED_NEW表示當(dāng)前方法必須運(yùn)行在它自己的事務(wù)中。一個(gè)新的事務(wù)將被啟動(dòng)。如果存在當(dāng)前事務(wù),在該方法執(zhí)行期間,當(dāng)前事務(wù)會(huì)被掛起。如果使用JTATransactionManager的話(huà),那么需要訪(fǎng)問(wèn)TransactionManagerPROPAGATION_NOT_SUPPORTED表示該方法不應(yīng)該運(yùn)行在事務(wù)中。如果存在當(dāng)前事務(wù),在該方法運(yùn)行期間,當(dāng)前事務(wù)將被掛起。如果使用JTATransactionManager的話(huà),那么需要訪(fǎng)問(wèn)TransactionManagerPROPAGATION_NEVER表示當(dāng)前方法不應(yīng)該運(yùn)行在事務(wù)上下文中。如果當(dāng)前正有一個(gè)事務(wù)在運(yùn)行,那么會(huì)拋出異常PROPAGATION_NESTED表示如果當(dāng)前已經(jīng)存在一個(gè)事務(wù),那么該方法將會(huì)在嵌套事務(wù)中運(yùn)行。嵌套的事務(wù)可以獨(dú)立于當(dāng)前事務(wù)進(jìn)行單獨(dú)地提交或回滾。如果當(dāng)前事務(wù)不存在,那么其行為與PROPAGATION_REQUIRED一樣。注意各廠(chǎng)商對(duì)這種傳播行為的支持是有所差異的??梢詤⒖假Y源管理器的文檔來(lái)確認(rèn)它們是否支持嵌套事務(wù)注:以下具體講解傳播行為的內(nèi)容參考自Spring事務(wù)機(jī)制詳解

〔1〕PROPAGATION_REQUIRED如果存在一個(gè)事務(wù),那么支持當(dāng)前事務(wù)。如果沒(méi)有事務(wù)那么開(kāi)啟一個(gè)新的事務(wù)。//事務(wù)屬性PROPAGATION_REQUIREDmethodA{……methodB();……}//事務(wù)屬性PROPAGATION_REQUIREDmethodB{……}使用spring聲明式事務(wù),spring使用AOP來(lái)支持聲明式事務(wù),會(huì)根據(jù)事務(wù)屬性,自動(dòng)在方法調(diào)用之前決定是否開(kāi)啟一個(gè)事務(wù),并在方法執(zhí)行之后決定事務(wù)提交或回滾事務(wù)。單獨(dú)調(diào)用methodB方法:main{metodB();}相當(dāng)于Main{Connectioncon=null;try{con=getConnection();con.setAutoCommit(false);//方法調(diào)用methodB();//提交事務(wù)conmit();}Catch(RuntimeExceptionex){//回滾事務(wù)con.rollback();}finally{//釋放資源closeCon();}}Spring保證在methodB方法中所有的調(diào)用都獲得到一個(gè)相同的連接。在調(diào)用methodB時(shí),沒(méi)有一個(gè)存在的事務(wù),所以獲得一個(gè)新的連接,開(kāi)啟了一個(gè)新的事務(wù)。

單獨(dú)調(diào)用MethodA時(shí),在MethodA內(nèi)又會(huì)調(diào)用MethodB.執(zhí)行效果相當(dāng)于:main{Connectioncon=null;try{con=getConnection();methodA();conmit();}catch(RuntimeExceptionex){con.rollback();}finally{closeCon();}}調(diào)用MethodA時(shí),環(huán)境中沒(méi)有事務(wù),所以開(kāi)啟一個(gè)新的事務(wù).當(dāng)在MethodA中調(diào)用MethodB時(shí),環(huán)境中已經(jīng)有了一個(gè)事務(wù),所以methodB就參加當(dāng)前事務(wù)?!?〕PROPAGATION_SUPPORTS如果存在一個(gè)事務(wù),支持當(dāng)前事務(wù)。如果沒(méi)有事務(wù),那么非事務(wù)的執(zhí)行。但是對(duì)于事務(wù)同步的事務(wù)管理器,PROPAGATION_SUPPORTS與不使用事務(wù)有少許不同。//事務(wù)屬性PROPAGATION_REQUIREDmethodA(){methodB();}//事務(wù)屬性PROPAGATION_SUPPORTSmethodB(){……}單純的調(diào)用methodB時(shí),methodB方法是非事務(wù)的執(zhí)行的。當(dāng)調(diào)用methdA時(shí),methodB那么參加了methodA的事務(wù)中,事務(wù)地執(zhí)行?!?〕PROPAGATION_MANDATORY如果已經(jīng)存在一個(gè)事務(wù),支持當(dāng)前事務(wù)。如果沒(méi)有一個(gè)活動(dòng)的事務(wù),那么拋出異常。//事務(wù)屬性PROPAGATION_REQUIREDmethodA(){methodB();}//事務(wù)屬性PROPAGATION_MANDATORYmethodB(){……}當(dāng)單獨(dú)調(diào)用methodB時(shí),因?yàn)楫?dāng)前沒(méi)有一個(gè)活動(dòng)的事務(wù),那么會(huì)拋出異常thrownewIllegalTransactionStateException(“Transactionpropagation‘mandatory’butnoexistingtransactionfound〞);當(dāng)調(diào)用methodA時(shí),methodB那么參加到methodA的事務(wù)中,事務(wù)地執(zhí)行?!?〕PROPAGATION_REQUIRES_NEW總是開(kāi)啟一個(gè)新的事務(wù)。如果一個(gè)事務(wù)已經(jīng)存在,那么將這個(gè)存在的事務(wù)掛起。//事務(wù)屬性PROPAGATION_REQUIREDmethodA(){doSomeThingA();methodB();doSomeThingB();}//事務(wù)屬性PROPAGATION_REQUIRES_NEWmethodB(){……}調(diào)用A方法:main(){methodA();}相當(dāng)于main(){TransactionManagertm=null;try{//獲得一個(gè)JTA事務(wù)管理器tm=getTransactionManager();tm.begin();//開(kāi)啟一個(gè)新的事務(wù)Transactionts1=tm.getTransaction();doSomeThing();tm.suspend();//掛起當(dāng)前事務(wù)try{tm.begin();//重新開(kāi)啟第二個(gè)事務(wù)Transactionts2=tm.getTransaction();methodB();ts2mit();//提交第二個(gè)事務(wù)}Catch(RunTimeExceptionex){ts2.rollback();//回滾第二個(gè)事務(wù)}finally{//釋放資源}//methodB執(zhí)行完后,恢復(fù)第一個(gè)事務(wù)tm.resume(ts1);doSomeThingB();ts1mit();//提交第一個(gè)事務(wù)}catch(RunTimeExceptionex){ts1.rollback();//回滾第一個(gè)事務(wù)}finally{//釋放資源}}在這里,我把ts1稱(chēng)為外層事務(wù),ts2稱(chēng)為內(nèi)層事務(wù)。從上面的代碼可以看出,ts2與ts1是兩個(gè)獨(dú)立的事務(wù),互不相干。Ts2是否成功并不依賴(lài)于ts1。如果methodA方法在調(diào)用methodB方法后的doSomeThingB方法失敗了,而methodB方法所做的結(jié)果依然被提交。而除了methodB之外的其它代碼導(dǎo)致的結(jié)果卻被回滾了。使用PROPAGATION_REQUIRES_NEW,需要使用JtaTransactionManager作為事務(wù)管理器。〔5〕PROPAGATION_NOT_SUPPORTED總是非事務(wù)地執(zhí)行,并掛起任何存在的事務(wù)。使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作為事務(wù)管理器?!泊a例如同上,可同理推出〕〔6〕PROPAGATION_NEVER總是非事務(wù)地執(zhí)行,如果存在一個(gè)活動(dòng)事務(wù),那么拋出異常?!?〕PROPAGATION_NESTED如果一個(gè)活動(dòng)的事務(wù)存在,那么運(yùn)行在一個(gè)嵌套的事務(wù)中.如果沒(méi)有活動(dòng)事務(wù),那么按TransactionDefinition.PROPAGATION_REQUIRED屬性執(zhí)行。這是一個(gè)嵌套事務(wù),使用JDBC3.0驅(qū)動(dòng)時(shí),僅僅支持DataSourceTransactionManager作為事務(wù)管理器。需要JDBC驅(qū)動(dòng)的類(lèi)。有一些JTA的事務(wù)管理器實(shí)現(xiàn)可能也提供了同樣的功能。使用PROPAGATION_NESTED,還需要把PlatformTransactionManager的nestedTransactionAllowed屬性設(shè)為true;而nestedTransactionAllowed屬性值默認(rèn)為false。//事務(wù)屬性PROPAGATION_REQUIREDmethodA(){doSomeThingA();methodB();doSomeThingB();}//事務(wù)屬性PROPAGATION_NESTEDmethodB(){……}如果單獨(dú)調(diào)用methodB方法,那么按REQUIRED屬性執(zhí)行。如果調(diào)用methodA方法,相當(dāng)于下面的效果:main(){Connectioncon=null;Savepointsavepoint=null;try{con=getConnection();con.setAutoCommit(false);doSomeThingA();savepoint=con2.setSavepoint();try{methodB();}catch(RuntimeExceptionex){con.rollback(savepoint);}finally{//釋放資源}doSomeThingB();conmit();}catch(RuntimeExceptionex){con.rollback();}finally{//釋放資源}}當(dāng)methodB方法調(diào)用之前,調(diào)用setSavepoint方法,保存當(dāng)前的狀態(tài)到savepoint。如果methodB方法調(diào)用失敗,那么恢復(fù)到之前保存的狀態(tài)。但是需要注意的是,這時(shí)的事務(wù)并沒(méi)有進(jìn)行提交,如果后續(xù)的代碼(doSomeThingB()方法)調(diào)用失敗,那么回滾包括methodB方法的所有操作。嵌套事務(wù)一個(gè)非常重要的概念就是內(nèi)層事務(wù)依賴(lài)于外層事務(wù)。外層事務(wù)失敗時(shí),會(huì)回滾內(nèi)層事務(wù)所做的動(dòng)作。而內(nèi)層事務(wù)操作失敗并不會(huì)引起外層事務(wù)的回滾。PROPAGATION_NESTED與PROPAGATION_REQUIRES_NEW的區(qū)別:它們非常類(lèi)似,都像一個(gè)嵌套事務(wù),如果不存在一個(gè)活動(dòng)的事務(wù),都會(huì)開(kāi)啟一個(gè)新的事務(wù)。使用PROPAGATION_REQUIRES_NEW時(shí),內(nèi)層事務(wù)與外層事務(wù)就像兩個(gè)獨(dú)立的事務(wù)一樣,一旦內(nèi)層事務(wù)進(jìn)行了提交后,外層事務(wù)不能對(duì)其進(jìn)行回滾。兩個(gè)事務(wù)互不影響。兩個(gè)事務(wù)不是一個(gè)真正的嵌套事務(wù)。同時(shí)它需要JTA事務(wù)管理器的支持。使用PROPAGATION_NESTED時(shí),外層事務(wù)的回滾可以引起內(nèi)層事務(wù)的回滾。而內(nèi)層事務(wù)的異常并不會(huì)導(dǎo)致外層事務(wù)的回滾,它是一個(gè)真正的嵌套事務(wù)。DataSourceTransactionManager使用savepoint支持PROPAGATION_NESTED時(shí),需要JDBC3.0以上驅(qū)動(dòng)及1.4以上的JDK版本支持。其它的JTATrasactionManager實(shí)現(xiàn)可能有不同的支持方式。PROPAGATION_REQUIRES_NEW啟動(dòng)一個(gè)新的,不依賴(lài)于環(huán)境的“內(nèi)部〞事務(wù).這個(gè)事務(wù)將被完全commited或rolledback而不依賴(lài)于外部事務(wù),它擁有自己的隔離范圍,自己的鎖,等等.當(dāng)內(nèi)部事務(wù)開(kāi)始執(zhí)行時(shí),外部事務(wù)將被掛起,內(nèi)務(wù)事務(wù)結(jié)束時(shí),外部事務(wù)將繼續(xù)執(zhí)行。另一方面,PROPAGATION_NESTED開(kāi)始一個(gè)“嵌套的〞事務(wù),它是已經(jīng)存在事務(wù)的一個(gè)真正的子事務(wù).潛套事務(wù)開(kāi)始執(zhí)行時(shí),它將取得一個(gè)savepoint.如果這個(gè)嵌套事務(wù)失敗,我們將回滾到此savepoint.潛套事務(wù)是外部事務(wù)的一局部,只有外部事務(wù)結(jié)束后它才會(huì)被提交。由此可見(jiàn),PROPAGATION_REQUIRES_NEW和PROPAGATION_NESTED的最大區(qū)別在于,PROPAGATION_REQUIRES_NEW完全是一個(gè)新的事務(wù),而PROPAGATION_NESTED那么是外部事務(wù)的子事務(wù),如果外部事務(wù)commit,嵌套事務(wù)也會(huì)被commit,這個(gè)規(guī)那么同樣適用于rollback.PROPAGATION_REQUIRED應(yīng)該是我們首先的事務(wù)傳播行為。它能夠滿(mǎn)足我們大多數(shù)的事務(wù)需求。2.2.2隔離級(jí)別事務(wù)的第二個(gè)維度就是隔離級(jí)別〔isolationlevel〕。隔離級(jí)別定義了一個(gè)事務(wù)可能受其他并發(fā)事務(wù)影響的程度。

〔1〕并發(fā)事務(wù)引起的問(wèn)題

在典型的應(yīng)用程序中,多個(gè)事務(wù)并發(fā)運(yùn)行,經(jīng)常會(huì)操作相同的數(shù)據(jù)來(lái)完成各自的任務(wù)。并發(fā)雖然是必須的,但可能會(huì)導(dǎo)致一下的問(wèn)題。臟讀〔Dirtyreads〕——臟讀發(fā)生在一個(gè)事務(wù)讀取了另一個(gè)事務(wù)改寫(xiě)但尚未提交的數(shù)據(jù)時(shí)。如果改寫(xiě)在稍后被回滾了,那么第一個(gè)事務(wù)獲取的數(shù)據(jù)就是無(wú)效的。不可重復(fù)讀〔Nonrepeatableread〕——不可重復(fù)讀發(fā)生在一個(gè)事務(wù)執(zhí)行相同的查詢(xún)兩次或兩次以上,但是每次都得到不同的數(shù)據(jù)時(shí)。這通常是因?yàn)榱硪粋€(gè)并發(fā)事務(wù)在兩次查詢(xún)期間進(jìn)行了更新?;米x〔Phantomread〕——幻讀與不可重復(fù)讀類(lèi)似。它發(fā)生在一個(gè)事務(wù)〔T1〕讀取了幾行數(shù)據(jù),接著另一個(gè)并發(fā)事務(wù)〔T2〕插入了一些數(shù)據(jù)時(shí)。在隨后的查詢(xún)中,第一個(gè)事務(wù)〔T1〕就會(huì)發(fā)現(xiàn)多了一些原本不存在的記錄。不可重復(fù)讀與幻讀的區(qū)別不可重復(fù)讀的重點(diǎn)是修改:

同樣的條件,你讀取過(guò)的數(shù)據(jù),再次讀取出來(lái)發(fā)現(xiàn)值不一樣了

例如:在事務(wù)1中,Mary讀取了自己的工資為1000,操作并沒(méi)有完成con1=getConnection();selectsalaryfromemployeeempId="Mary";在事務(wù)2中,這時(shí)財(cái)務(wù)人員修改了Mary的工資為2000,并提交了事務(wù).con2=getConnection();updateemployeesetsalary=2000;con2mit();在事務(wù)1中,Mary再次讀取自己的工資時(shí),工資變?yōu)榱?000//con1selectsalaryfromemployeeempId="Mary";在一個(gè)事務(wù)中前后兩次讀取的結(jié)果并不一致,導(dǎo)致了不可重復(fù)讀?;米x的重點(diǎn)在于新增或者刪除:

同樣的條件,第1次和第2次讀出來(lái)的記錄數(shù)不一樣

例如:目前工資為1000的員工有10人。事務(wù)1,讀取所有工資為1000的員工。con1=getConnection();Select*fromemployeewheresalary=1000;共讀取10條記錄這時(shí)另一個(gè)事務(wù)向employee表插入了一條員工記錄,工資也為1000con2=getConnection();Insertintoemployee(empId,salary)values("Lili",1000);con2mit();事務(wù)1再次讀取所有工資為1000的員工//con1select*fromemployeewheresalary=1000;共讀取到了11條記錄,這就產(chǎn)生了幻像讀。從總的結(jié)果來(lái)看,似乎不可重復(fù)讀和幻讀都表現(xiàn)為兩次讀取的結(jié)果不一致。但如果你從控制的角度來(lái)看,兩者的區(qū)別就比擬大。

對(duì)于前者,只需要鎖住滿(mǎn)足條件的記錄。

對(duì)于后者,要鎖住滿(mǎn)足條件及其相近的記錄?!?〕隔離級(jí)別隔離級(jí)別含義ISOLATION_DEFAULT使用后端數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別ISOLATION_READ_UNCOMMITTED最低的隔離級(jí)別,允許讀取尚未提交的數(shù)據(jù)變更,可能會(huì)導(dǎo)致臟讀、幻讀或不可重復(fù)讀ISOLATION_READ_COMMITTED允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù),可以阻止臟讀,但是幻讀或不可重復(fù)讀仍有可能發(fā)生ISOLATION_REPEATABLE_READ對(duì)同一字段的屢次讀取結(jié)果都是一致的,除非數(shù)據(jù)是被本身事務(wù)自己所修改,可以阻止臟讀和不可重復(fù)讀,但幻讀仍有可能發(fā)生ISOLATION_SERIALIZABLE最高的隔離級(jí)別,完全服從ACID的隔離級(jí)別,確保阻止臟讀、不可重復(fù)讀以及幻讀,也是最慢的事務(wù)隔離級(jí)別,因?yàn)樗ǔJ峭ㄟ^(guò)完全鎖定事務(wù)相關(guān)的數(shù)據(jù)庫(kù)表來(lái)實(shí)現(xiàn)的2.2.3只讀事務(wù)的第三個(gè)特性是它是否為只讀事務(wù)。如果事務(wù)只對(duì)后端的數(shù)據(jù)庫(kù)進(jìn)行該操作,數(shù)據(jù)庫(kù)可以利用事務(wù)的只讀特性來(lái)進(jìn)行一些特定的優(yōu)化。通過(guò)將事務(wù)設(shè)置為只讀,你就可以給數(shù)據(jù)庫(kù)一個(gè)時(shí)機(jī),讓它應(yīng)用它認(rèn)為適宜的優(yōu)化措施。2.2.4事務(wù)超時(shí)為了使應(yīng)用程序很好地運(yùn)行,事務(wù)不能運(yùn)行太長(zhǎng)的時(shí)間。因?yàn)槭聞?wù)可能涉及對(duì)后端數(shù)據(jù)庫(kù)的鎖定,所以長(zhǎng)時(shí)間的事務(wù)會(huì)不必要的占用數(shù)據(jù)庫(kù)資源。事務(wù)超時(shí)就是事務(wù)的一個(gè)定時(shí)器,在特定時(shí)間內(nèi)事務(wù)如果沒(méi)有執(zhí)行完畢,那么就會(huì)自動(dòng)回滾,而不是一直等待其結(jié)束。2.2.5回滾規(guī)那么事務(wù)五邊形的最后一個(gè)方面是一組規(guī)那么,這些規(guī)那么定義了哪些異常會(huì)導(dǎo)致事務(wù)回滾而哪些不會(huì)。默認(rèn)情況下,事務(wù)只有遇到運(yùn)行期異常時(shí)才會(huì)回滾,而在遇到檢查型異常時(shí)不會(huì)回滾〔這一行為與EJB的回滾行為是一致的〕

但是你可以聲明事務(wù)在遇到特定的檢查型異常時(shí)像遇到運(yùn)行期異常那樣回滾。同樣,你還可以聲明事務(wù)遇到特定的異常不回滾,即使這些異常是運(yùn)行期異常。2.3事務(wù)狀態(tài)上面講到的調(diào)用PlatformTransactionManager接口的getTransaction()的方法得到的是TransactionStatus接口的一個(gè)實(shí)現(xiàn),這個(gè)接口的內(nèi)容如下:publicinterfaceTransactionStatus{booleanisNewTransaction();//是否是新的事物booleanhasSavepoint();//是否有恢復(fù)點(diǎn)voidsetRollbackOnly();//設(shè)置為只回滾booleanisRollbackOnly();//是否為只回滾booleanisCompleted;//是否已完成}可以發(fā)現(xiàn)這個(gè)接口描述的是一些處理事務(wù)提供簡(jiǎn)單的控制事務(wù)執(zhí)行和查詢(xún)事務(wù)狀態(tài)的方法,在回滾或提交的時(shí)候需要應(yīng)用對(duì)應(yīng)的事務(wù)狀態(tài)。3編程式事務(wù)3.1編程式和聲明式事務(wù)的區(qū)別Spring提供了對(duì)編程式事務(wù)和聲明式事務(wù)的支持,編程式事務(wù)允許用戶(hù)在代碼中精確定義事務(wù)的邊界,而聲明式事務(wù)〔基于A(yíng)OP〕有助于用戶(hù)將操作與事務(wù)規(guī)那么進(jìn)行解耦。

簡(jiǎn)單地說(shuō),編程式事務(wù)侵入到了業(yè)務(wù)代碼里面,但是提供了更加詳細(xì)的事務(wù)管理;而聲明式事務(wù)由于基于A(yíng)OP,所以既能起到事務(wù)管理的作用,又可以不影響業(yè)務(wù)代碼的具體實(shí)現(xiàn)。3.2如何實(shí)現(xiàn)編程式事務(wù)?Spring提供兩種方式的編程式事務(wù)管理,分別是:使用TransactionTemplate和直接使用PlatformTransactionManager。3.2.1使用TransactionTemplate采用TransactionTemplate和采用其他Spring模板,如JdbcTempalte和HibernateTemplate是一樣的方法。它使用回調(diào)方法,把應(yīng)用程序從處理取得和釋放資源中解脫出來(lái)。如同其他模板,TransactionTemplate是線(xiàn)程平安的。代碼片段:TransactionTemplatett=newTransactionTemplate();//新建一個(gè)TransactionTemplateObjectresult=tt.execute(newTransactionCallback(){publicObjectdoTransaction(TransactionStatusstatus){updateOperation();returnresultOfUpdateOperation();}});//執(zhí)行execute方法進(jìn)行事務(wù)管理使用TransactionCallback()可以返回一個(gè)值。如果使用TransactionCallbackWithoutResult那么沒(méi)有返回值。3.2.2使用PlatformTransactionManager例如代碼如下:DataSourceTransactionManagerdataSourceTransactionManager=newDataSourceTransactionManager();//定義一個(gè)某個(gè)框架平臺(tái)的TransactionManager,如JDBC、HibernatedataSourceTransactionManager.setDataSource(this.getJdbcTemplate().getDataSource());//設(shè)置數(shù)據(jù)源DefaultTransactionDefinitiontransDef=newDefaultTransactionDefinition();//定義事務(wù)屬性transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);//設(shè)置傳播行為屬性TransactionStatusstatus=dataSourceTransactionManager.getTransaction(transDef);//獲得事務(wù)狀態(tài)try{//數(shù)據(jù)庫(kù)操作dataSourceTransactionManagermit(status);//提交}catch(Exceptione){dataSourceTransactionManager.rollback(status);//回滾}4聲明式事務(wù)4.1配置方式注:以下配置代碼參考自Spring事務(wù)配置的五種方式根據(jù)代理機(jī)制的不同,總結(jié)了五種Spring事務(wù)的配置方式,配置文件如下:〔1〕每個(gè)Bean都有一個(gè)代理<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns=":///schema/beans"xmlns:xsi=":///2001/XMLSchema-instance"xmlns:context=":///schema/context"xmlns:aop=":///schema/aop"xsi:schemaLocation:///schema/aop:///schema/aop/spring-aop-2.5.xsd"><beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><propertyname="configLocation"value="classpath"/><propertyname="configurationClass"value=""/></bean><!--定義事務(wù)管理器〔聲明式的事務(wù)〕--><beanid="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><propertyname="sessionFactory"ref="sessionFactory"/></bean><!--配置DAO--><beanid="userDaoTarget"class=""><propertyname="sessionFactory"ref="sessionFactory"/></bean><beanid="userDao"class="erceptor.TransactionProxyFactoryBean"><!--配置事務(wù)管理器--><propertyname="transactionManager"ref="transactionManager"/><propertyname="target"ref="userDaoTarget"/><propertyname="proxyInterfaces"value=""/><!--配置事務(wù)屬性--><propertyname="transactionAttributes"><props><propkey="*">PROPAGATION_REQUIRED</prop></props></property></bean></beans>〔2〕所有Bean共享一個(gè)代理基類(lèi)<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns=":///schema/beans"xmlns:xsi=":///2001/XMLSchema-instance"xmlns:context=":///schema/context"xmlns:aop=":///schema/aop"xsi:schemaLocation:///schema/aop:///schema/aop/spring-aop-2.5.xsd"><beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><propertyname="configLocation"value="classpath"/><propertyname="configurationClass"value=""/></bean><!--定義事務(wù)管理器〔聲明式的事務(wù)〕--><beanid="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><propertyname="sessionFactory"ref="sessionFactory"/></bean><beanid="transactionBase"class="erceptor.TransactionProxyFactoryBean"lazy-init="true"abstract="true"><!--配置事務(wù)管理器--><propertyname="transactionManager"ref="transactionManager"/><!--配置事務(wù)屬性--><propertyname="transactionAttributes"><props><propkey="*">PROPAGATION_REQUIRED</prop></props></property></bean><!--配置DAO--><beanid="userDaoTarget"class=""><propertyname="sessionFactory"ref="sessionFactory"/></bean><beanid="userDao"parent="transactionBase"><propertyname="target"ref="userDaoTarget"/></bean></beans>〔3〕使用攔截器<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns=":///schema/beans"xmlns:xsi=":///2001/XMLSchema-instance"xmlns:context=":///schema/context"xmlns:aop=":///schema/aop"xsi:schemaLocation:///schema/aop:///schema/aop/spring-aop-2.5.xsd"><beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><propertyname="configLocation"value="classpath"/><propertyname="configurationClass"value=""/></bean><!--定義事務(wù)管理器〔聲明式的事務(wù)〕--><beanid="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><propertyname="sessionFactory"ref="sessionFactory"/></bean><beanid="transactionInterceptor"class="erceptor.TransactionInterceptor"><propertyname="transactionManager"ref="transactionManager"/><!--配置事務(wù)屬性--><propertyname="transactionAttributes"><props><propkey="*">PROPAGATION_REQUIRED</prop></props></property></bean><beanclass="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><propertyname="beanNames"><list><value>*Dao</value></list></property><propertyname="interceptorNames"><list><value>transactionInterceptor</value></list></property></bean><!--配置DAO--><beanid="userDao"class=""><propertyname="sessionFactory"ref="sessionFactory"/></bean></beans>〔4〕使用tx標(biāo)簽配置的攔截器<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns=":///schema/beans"xmlns:xsi=":///2001/XMLSchema-instance"xmlns:context=":///schema/context"xmlns:aop=":///schema/aop"xmlns:tx=":///schema/tx"xsi:schemaLocation:///schema/tx:///schema/tx/spring-tx-2.5.xsd"><context:annotation-config/><context:component-scanbase-package="com.bluesky"/><beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><propertyname="configLocation"value="classpath"/><propertyname="configurationClass"value=""/></bean><!--定義事務(wù)管理器〔聲明式的事務(wù)〕--><beanid="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><propertyname="sessionFactory"ref="sessionFactory"/></bean><tx:adviceid="txAdvice"transaction-manager="transactionManager"><tx:attributes><tx:methodname="*"propagation="REQUIRED"/></tx:attributes></tx:advice><aop:config><aop:pointcutid="interceptorPointCuts"expression="execution(*.*.*(..))"/><aop:advisoradvice-ref="txAdvice"pointcut-ref="interceptorPointCuts"/></aop:config></beans>〔5〕全注解<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns=":///schema/beans"xmlns:xsi=":///2001/XMLSchema-instance"xmlns:context=":///schema/context"xmlns:aop=":///schema/aop"xmlns:tx=":///schema/tx"xsi:schemaLocation:///schema/tx:///schema/tx/spring-tx-2.5.xsd"><context:annotation-config/><context:component-scanbase-package="com.bluesky"/><tx:annotation-driventransaction-manager="transactionManager"/><beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><propertyname="configLocation"value="classpath"/><propertyname="configurationClass"value=""/></bean><!--定義事務(wù)管理器〔聲明式的事務(wù)〕--><beanid="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><propertyname="sessionFactory"ref="sessionFactory"/></bean></beans>此時(shí)在DAO上需加上@Transactional注解,如下:packagecom.bluesky.spring.dao;importjava.util.List;importorg.hibernate.SessionFactory;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.orm.hibernate3.support.HibernateDaoSupport;importorg.springframework.stereotypeponent;importcom.bluesky.spring.domain.User;@Transactional@Component("userDao")publicclassUserDaoImplextendsHibernateDaoSupportimplementsUserDao{publicList<User>listUsers(){returnthis.getSession().createQuery("fromUser").list();}}4.2一個(gè)聲明式事務(wù)的實(shí)例注:該實(shí)例參考自Spring中的事務(wù)管理實(shí)例詳解首先是數(shù)據(jù)庫(kù)表

book(isbn,book_name,price)

account(username,balance)book_stock(isbn,stock)然后是XML配置<beansxmlns=":///schema/beans"xmlns:xsi=":///2001/XMLSchema-instance"xmlns:context=":///schema/context"xmlns:aop=":///schema/aop"xmlns:tx=":///schema/tx"xsi:schemaLocation:///schema/tx:///schema/tx/spring-tx-2.5.xsd"><importresource="applicationContext-db.xml"/><context:component-scanbase-package=""></context:component-scan><tx:annotation-driventransaction-manager="txManager"/><beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><propertyname="dataSource"ref="dataSource"/></bean></beans>使用的類(lèi)BookShopDaopackagecom.springinaction.transaction;publicinterfaceBookShopDao{//根據(jù)書(shū)號(hào)獲取書(shū)的單價(jià)publicintfindBookPriceByIsbn(Stringisbn);//更新書(shū)的庫(kù)存,使書(shū)號(hào)對(duì)應(yīng)的庫(kù)存-1publicvoidupdateBookStock(Stringisbn);//更新用戶(hù)的賬戶(hù)余額:account的balance-pricepublicvoidupdateUserAccount(Stringusername,intprice);}BookShopDaoImplpackagecom.springinaction.transaction;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.jdbc.core.JdbcTemplate;importorg.springframework.stereotype.Repository;@Repository("bookShopDao")publicclassBookShopDaoImplimplementsBookShopDao{@AutowiredprivateJdbcTemplateJdbcTemplate;@OverridepublicintfindBookPriceByIsbn(Stringisbn){Stringsql="SELECTpriceFROMbookWHEREisbn=?";returnJdbcTemplate.queryForObject(sql,Integer.class,isbn);}@OverridepublicvoidupdateBookStock(Stringisbn){//檢查書(shū)的庫(kù)存是否足夠,假設(shè)不夠,那么拋出異常Stringsql2="SELECTstockFROMbook_stockWHEREisbn=?";intstock=JdbcTemplate.queryForObject(sql2,Integer.class,isbn);if(stock==0){thrownewBookStockException("庫(kù)存缺乏!");}Stringsql="UPDATEbook_stockSETstock=stock-1WHEREisbn=?";JdbcTemplate.update(sql,isbn);}@OverridepublicvoidupdateUserAccount(Stringusername,intprice){//檢查余額是否缺乏,假設(shè)缺乏,那么拋出異常Stringsql2="SELECTbalanceFROMaccountWHEREusername=?";intbalance=JdbcTemplate.queryForObject(sql2,Integer.class,username);if(balance<price){thrownewUserAccountException("余額缺乏!");}Stringsql="UPDATEaccountSETbalance=balance-?WHEREusername=?";JdbcTemplate.update(sql,price,username);}}BookShopServicepackagecom.springinaction.transaction;publicinterfaceBookShopService{publicvoidpurchase(Stringusername,Stringisbn);}BookShopServiceImplpackagecom.springinaction.transaction;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Isolation;importorg.springframework.transaction.annotation.Propagation;importorg.springframework.transaction.annotation.Transactional;@Service("bookShopService")publicclassBookShopServiceImplimplementsBookShopService{@AutowiredprivateBookShopDaobookShopDao;/***1.添加事務(wù)注解*使用propagation指定事務(wù)的傳播行為,即當(dāng)前的事務(wù)方法被另外一個(gè)事務(wù)方法調(diào)用時(shí)如何使用事務(wù)。*默認(rèn)取值為REQUIRED,即使用調(diào)用方法的事務(wù)*REQUIRES_NEW:使用自己的事務(wù),調(diào)用的事務(wù)方法的事務(wù)被掛起。**2.使用isolation指定事務(wù)的隔離級(jí)別,最常用的取值為READ_COMMITTED*3.默認(rèn)情況下Spring的聲明式事務(wù)對(duì)所有的運(yùn)行時(shí)異常進(jìn)行回滾,也可以通過(guò)對(duì)應(yīng)的屬性進(jìn)行設(shè)置。通常情況下,默認(rèn)值即可。*4.使用readOnly指定事務(wù)是否為只讀。表示這個(gè)事務(wù)只讀取數(shù)據(jù)但不更新數(shù)據(jù),這樣可以幫助數(shù)據(jù)庫(kù)引擎優(yōu)化事務(wù)。假設(shè)真的是一個(gè)只讀取數(shù)據(jù)庫(kù)值得方法,應(yīng)設(shè)置readOnly=true*5.使用timeOut指定強(qiáng)制回滾之前事務(wù)可以占用的時(shí)間。*/@Transactional(propagation=Propagation.REQUIRES_NEW,isolation=Isolation.READ_COMMITTED,noRollbackFor={UserAccountException.class},readOnly=true,timeout=3)@Overridepublicvoidpurchase(Stringusername,Stringisbn){//1.獲取書(shū)的單價(jià)intprice=bookShopDao.findBookPriceByIsbn(isbn);//2.更新書(shū)的庫(kù)存bookShopDao.updateBookStock(isbn);//3.更新用戶(hù)余額bookShopDao.updateUserAccount(username,price);}}Cashierpackagecom.springinaction.transaction;importjava.util.List;publicinterfaceCashier{publicvoidcheckout(Stringusername,List<String>isbns);}CashierImpl:CashierImpl.checkout和bookShopService.purchase聯(lián)合測(cè)試了事務(wù)的傳播行為packagecom.springinaction.transaction;importjava.util.List;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;@Service("cashier")publicclassCashierImplimplementsCashier{@Autowired

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論