事務的出現是爲了保證數據的完整性和一致性,爲了防止意外的中斷致使數據出現錯誤.spring
在Spring中事務的主要使用方式有兩種,一種是編程式事務管理另外一種是聲明式事務管理.編程式事務使用的是JDBC的原生API須要編寫大量代碼太過麻煩。所以如今Spring主要使用的是聲明式事務編程,Spring中的聲明式事務編程是基於AOP模式的,也就是在@before以前建立一個事物,@AfterRetuning以前確認一下事務是否須要回滾.聲明式事務的最大優勢就是不用寫一堆代碼而能夠直接經過註解(基於@Transaction註解)和配置文件(基於tx和aop命名空間)完成事務管理.數據庫
XML文件express
<!--引入事務管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="pooledDataSource"></property> </bean> <!--依賴tx名稱空間,開啓事務註解--> <tx:annotation-driven transaction-manager="transactionManager"/>
@Transaction註解主要是添加在Service組件的方法下編程
@Transactional(propagation=Propagation.REQUIRES,isolation=READ_COMMITTED) public void updateBook(String name,int price){ libaryDao.updateBook(name, price); }
<!--引入事務管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="pooledDataSource"></property> </bean> <aop:config> <!-- 配置事務切入點,哪些類哪些方法須要切入事務--> <aop:pointcut expression="execution(* com.libary.service*.*.*(..))" id="Point"/> <aop:advisor advice-ref="MyTx" pointcut-ref="Point"/> </aop:config> <!-- 配置事務管理器 --> transaction-manager="transactionManager": <tx:advice id="MyTx" transaction-manager="transactionManager"> <!--事務的屬性 --> <tx:attributes> <!--tx:method 指定了哪些方法須要加事務 --> <tx:method name="*"/> <tx:method name="update" propagation="REQUIRED" timeout="-1"/> <tx:method name="query*" read-only="true"/> </tx:attributes> </tx:advice>
與Aop的使用相同,事務使用的思想應該是,重要的事務使用xml配置,不重要的事務使用@Transaction.併發
noRollbackFor:指定異常事務不回滾.
rollbackFor:指定異常事務回滾(編譯時錯誤原本不回滾使其回滾,編譯時錯誤默認是不回滾的除非使用try catch捕捉錯誤,可是運行錯誤是必定進行回滾)
timeout:事務超出指定時間即回滾,防止事務佔用資源.
readOnly:只能夠添加在查詢事務上,能夠優化事務的查詢速度.
isolation:隔離級別下面重點提到.
propagation:傳播行爲下面重點提到.
多種事務嵌套運行時,下面的事務服從頂層事務的屬性.框架
事物的傳播行爲主要是爲了處理當有多個事務嵌套執行時,其中某個事務出現了錯誤,有哪些事務須要進行回滾.
如如下狀況優化
TestTx() { A事務(REQUIRED) { B事務(REQUIRED_NEW) { C事務(REQUIRED) { } } D事務(REQUIRED) { E事務(REQUIRED) { } } F事務(REQUIRED_NEW) } }
平常事務管理中主要特別注意的事務是REQUIRED和REQUIRED_NEW
REQUIRED。
REQUIRED:REQUIRED的意思是與他的上層事務同生共死,你們共用一個事物。即如上代碼,若是D出現錯誤了A也出現錯誤,你們一塊兒進行rollback。
REQUIRED_NEW:REQUIRED_NEW的意思是我本身玩我本身的,我本身有一個事物,例如F出現錯誤了,與A事務有太多關係。F進行rollback,A不rollback。
特殊狀況:如上代碼,若是D出現錯誤了,那麼即使F是REQUIRED_NEW也不會執行,由於到D已經就直接拋出錯誤了。
重要的一點:
1.無論哪裏出錯,已經執行完的REQUIRED_NEW都不會出錯。
2.嵌套事務中由最頂層事務來決定Timeout等屬性。spa
例:x=10; A事務修改x=5但還未commit; B讀出x=5; A進行rollback,x=10; B讀出的x=5是假數據
例:x=10; B事務讀取x=10; A事務修改x=5並commit; B再次讀取x=5,兩次讀取x不一樣;
例:x=10; B事務讀取x=10; A事務添加y=20,i=30; B再次讀取讀出x=10,,y=20,i=30.多出大量數據。
使用@Transaction的isolation=Propagation.?屬性設置隔離級別.代理
例:@Transactional(propagation=Propagation.REQUIRES_NEW,isolation=READ_COMMITTED)
READ_UNCOMMITTED(讀未提交):容許髒讀、不可重讀讀、幻讀.
READ_COMMITTED(讀已提交):容許不可重讀和幻讀,不容許髒讀.
REPEATABLE READ(可重複讀):容許幻讀,不容許髒讀和不可重複讀.
SERIALIZABLE(串行化):不容許髒讀、不可重複讀、幻讀.code
最後特別要注意的是千萬不要在某個Service組件中調用Service的事務方法(即不要調用本類方法),要記住Spring中的事物使用是基於AOP的,因此事務須要用代理對象,而直接在本類中調用的方法是沒法進行事務的。本類方法的嵌套無論調用多少個都是單個事務.
例: @Service public class LibaryService{ @Autowired LibaryDao libaryDao; @Transaction(propagation=Propagation.REQUIRES_NEW) public int updateBook(String name,int price) { libaryDao.update(name,price); } @Transaction(propagation=Propagation.REQUIRES_NEW) public Book QueryBook(int Id) { libaryDao.QueryBook(Id); } //如下代碼只有errorway()會被當成一個事物。而下方的updateBook()和QueryBook()由於是調用了本類方法,沒有使用代理對象,因此不會通過事務處理。 @Transaction public void errorway() { updateBook("三毛流浪記",56); QueryBook("射鵰英雄傳"); }