事务的属性
事務(wù)傳播屬性
當(dāng)事務(wù)方法被另一個(gè)事務(wù)方法調(diào)用時(shí), 必須指定事務(wù)應(yīng)該如何傳播. 例如: 方法可能繼續(xù)在現(xiàn)有事務(wù)中運(yùn)行, 也可能開啟一個(gè)新事務(wù), 并在自己的事務(wù)中運(yùn)行.
事務(wù)的傳播行為可以由傳播屬性指定. Spring 定義了 7? 種類傳播行為.
Spring 支持的事務(wù)傳播行為
需求
新定義 Cashier 接口: 表示客戶的結(jié)賬操作
修改數(shù)據(jù)表信息如下, 目的是用戶 Tom 在結(jié)賬時(shí), 余額只能支付第一本書, 不夠支付第二本書:
REQUIRED 傳播行為
當(dāng) bookService 的 purchase() 方法被另一個(gè)事務(wù)方法 checkout() 調(diào)用時(shí), 它默認(rèn)會(huì)在現(xiàn)有的事務(wù)內(nèi)運(yùn)行. 這個(gè)默認(rèn)的傳播行為就是 REQUIRED. 因此在 checkout() 方法的開始和終止邊界內(nèi)只有一個(gè)事務(wù). 這個(gè)事務(wù)只在 checkout() 方法結(jié)束的時(shí)候被提交, 結(jié)果用戶一本書都買不了
事務(wù)傳播屬性可以在 @Transactional 注解的 propagation 屬性中定義
REQUIRES_NEW 傳播行為
另一種常見的傳播行為是 REQUIRES_NEW. 它表示該方法必須啟動(dòng)一個(gè)新事務(wù), 并在自己的事務(wù)內(nèi)運(yùn)行. 如果有事務(wù)在運(yùn)行, 就應(yīng)該先掛起它.
在 Spring 2.x 事務(wù)通知中配置傳播屬性
在 Spring 2.x 事務(wù)通知中, 可以像下面這樣在 <tx:method> 元素中設(shè)定傳播事務(wù)屬性
并發(fā)事務(wù)所導(dǎo)致的問題
當(dāng)同一個(gè)應(yīng)用程序或者不同應(yīng)用程序中的多個(gè)事務(wù)在同一個(gè)數(shù)據(jù)集上并發(fā)執(zhí)行時(shí), 可能會(huì)出現(xiàn)許多意外的問題
并發(fā)事務(wù)所導(dǎo)致的問題可以分為下面三種類型:
–?臟讀: 對(duì)于兩個(gè)事物 T1, T2, T1? 讀取了已經(jīng)被 T2 更新但 還沒有被提交的字段. 之后, 若 T2 回滾, T1讀取的內(nèi)容就是臨時(shí)且無效的.
–?不可重復(fù)讀:對(duì)于兩個(gè)事物 T1, T2, T1? 讀取了一個(gè)字段, 然后 T2 更新了該字段. 之后, T1再次讀取同一個(gè)字段, 值就不同了.
–?幻讀:對(duì)于兩個(gè)事物 T1, T2, T1? 從一個(gè)表中讀取了一個(gè)字段, 然后 T2 在該表中插入了一些新的行. 之后, 如果 T1 再次讀取同一個(gè)表, 就會(huì)多出幾行.
事務(wù)的隔離級(jí)別
從理論上來說, 事務(wù)應(yīng)該彼此完全隔離, 以避免并發(fā)事務(wù)所導(dǎo)致的問題. 然而, 那樣會(huì)對(duì)性能產(chǎn)生極大的影響, 因?yàn)槭聞?wù)必須按順序運(yùn)行.
在實(shí)際開發(fā)中, 為了提升性能, 事務(wù)會(huì)以較低的隔離級(jí)別運(yùn)行.
事務(wù)的隔離級(jí)別可以通過隔離事務(wù)屬性指定
Spring 支持的事務(wù)隔離級(jí)別
事務(wù)的隔離級(jí)別要得到底層數(shù)據(jù)庫引擎的支持, 而不是應(yīng)用程序或者框架的支持.
Oracle 支持的 2 種事務(wù)隔離級(jí)別:READ_COMMITED , SERIALIZABLE
Mysql 支持 4 中事務(wù)隔離級(jí)別.
設(shè)置隔離事務(wù)屬性
用 @Transactional 注解聲明式地管理事務(wù)時(shí)可以在 @Transactional 的 isolation 屬性中設(shè)置隔離級(jí)別.
在 Spring 2.x 事務(wù)通知中, 可以在 <tx:method> 元素中指定隔離級(jí)別
設(shè)置回滾事務(wù)屬性
默認(rèn)情況下只有未檢查異常(RuntimeException和Error類型的異常)會(huì)導(dǎo)致事務(wù)回滾. 而受檢查異常不會(huì).
事務(wù)的回滾規(guī)則可以通過 @Transactional 注解的 rollbackFor 和 noRollbackFor 屬性來定義. 這兩個(gè)屬性被聲明為 Class[] 類型的, 因此可以為這兩個(gè)屬性指定多個(gè)異常類.
rollbackFor:? 遇到時(shí)必須進(jìn)行回滾
noRollbackFor: 一組異常類,遇到時(shí)必須不回滾
設(shè)置回滾事務(wù)屬性
在 Spring 2.x 事務(wù)通知中, 可以在 <tx:method> 元素中指定回滾規(guī)則. 如果有不止一種異常, 用逗號(hào)分隔.
超時(shí)和只讀屬性
由于事務(wù)可以在行和表上獲得鎖,? 因此長(zhǎng)事務(wù)會(huì)占用資源, 并對(duì)整體性能產(chǎn)生影響.
如果一個(gè)事物只讀取數(shù)據(jù)但不做修改, 數(shù)據(jù)庫引擎可以對(duì)這個(gè)事務(wù)進(jìn)行優(yōu)化.
超時(shí)事務(wù)屬性: 事務(wù)在強(qiáng)制回滾之前可以保持多久. 這樣可以防止長(zhǎng)期運(yùn)行的事務(wù)占用資源.
只讀事務(wù)屬性: 表示這個(gè)事務(wù)只讀取數(shù)據(jù)但不更新數(shù)據(jù), 這樣可以幫助數(shù)據(jù)庫引擎優(yōu)化事務(wù).
設(shè)置超時(shí)和只讀事務(wù)屬性
超時(shí)和只讀屬性可以在 @Transactional 注解中定義.超時(shí)屬性以秒為單位來計(jì)算.
在 Spring 2.x 事務(wù)通知中, 超時(shí)和只讀屬性可以在 <tx:method> 元素中進(jìn)行指定.
package com.learn.spring.tx.service;import java.util.List;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;@Service public class CashierImpl implements Cashier{@Autowiredprivate BookShopService bookShopService;@Override@Transactionalpublic void checkOut(String username, List<String> isbns) {for (String isbn : isbns) {bookShopService.buyBook(username, isbn);}}} package com.learn.spring.tx.service;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional;import com.learn.spring.tx.dao.BookShopDao; import com.learn.spring.tx.exception.UserAccountException;@Service //@Transactional //對(duì)該類中所有的方法都起作用 public class BookShopServiceImpl implements BookShopService{@Autowiredprivate BookShopDao bookShopDao ; /*** 事務(wù)的屬性:* propagation:事務(wù)的傳播行為.* REQUIRED:使用調(diào)用者的事務(wù)* REQUIRES_NEW:將調(diào)用者的事務(wù)掛起,使用自己的新事務(wù).* * isolation:事務(wù)的隔離級(jí)別,最常用的就是READ_COMMITTED* readOnly:指定事務(wù)是否為只讀. 如果是只讀事務(wù),代表這個(gè)事務(wù)只讀取數(shù)據(jù)庫的數(shù)據(jù).而不進(jìn)行修改操作 .* 若一個(gè)事務(wù)真的是只讀取數(shù)據(jù),就有必須要設(shè)置readOnly=true,可以幫助數(shù)據(jù)庫引擎進(jìn)行優(yōu)化* * rollbackFor* rollbackForClassName* noRollbackFor* noRollbackForClassName * * timeout:指定強(qiáng)制回滾前事務(wù)可以占用的時(shí)間。 為了避免一個(gè)事務(wù)占用過長(zhǎng)的時(shí)間.* */@Transactional(propagation=Propagation.REQUIRES_NEW,isolation=Isolation.READ_COMMITTED,readOnly=false/*noRollbackFor={UserAccountException.class}*//*timeout=3*/)public void buyBook(String username, String isbn) {try {Thread.sleep(5000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//1.查詢書的價(jià)格int price = bookShopDao.findBookPriceByIsbn(isbn);//2.更新書的庫存bookShopDao.updateBookStock(isbn);//3.更新用戶的余額bookShopDao.updateUserAccount(username, price); }// }?
超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
 
                            
                        