一. 事務(wù)特性ACID
- 原子性
- 一致性
- 隔離性
- 持久性
二. 事務(wù)管理器
Spring并不直接管理事務(wù),而是提供事務(wù)管理器接口,讓框架自己(包括JDBC、hibernate、JPA、JTA等)實(shí)現(xiàn)具體的事務(wù)管理。
2.1 spring提供的事務(wù)管理器接口
包括3個(gè)接口:獲取事務(wù)狀態(tài)、提交、回滾
package org.springframework.transaction;
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;
void commit(TransactionStatus var1) throws TransactionException;
void rollback(TransactionStatus var1) throws TransactionException;
}
2.2 具體實(shí)現(xiàn)(以JDBC為例)
DataSourceTransactionManager通過(guò)DataSource獲取到j(luò)ava.sql.Connection,再調(diào)用java.sql.Connection來(lái)管理事務(wù)
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="具體數(shù)據(jù)源"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
三. 事務(wù)基本屬性
上文提到的spring事務(wù)管理器接口中,用于獲取事務(wù)狀態(tài)的getTransaction方法參數(shù)定義了一個(gè)事務(wù)的基本屬性
TransactionStatus getTransaction(TransactionDefinition var1)
事務(wù)基本屬性包括5類(lèi):
- 傳播行為
- 隔離級(jí)別
- 是否只讀
- 超時(shí)時(shí)間
- 回滾規(guī)則
public interface TransactionDefinition {
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
String getName();
}
3.1 傳播行為 PROPAGATION
定義一個(gè)事務(wù)被另一個(gè)事務(wù)調(diào)用時(shí),兩個(gè)事務(wù)之間的關(guān)系,如:被調(diào)用事務(wù)合并到調(diào)用事務(wù)中運(yùn)行,或者獨(dú)立開(kāi)啟一個(gè)新事務(wù)運(yùn)行等。
Spring定義了七種傳播行為:
- require_new(本身執(zhí)行時(shí)是事務(wù),被事務(wù)調(diào)用時(shí)也不合并為同一個(gè)事務(wù))
- require(本身執(zhí)行時(shí)是事務(wù),被事務(wù)調(diào)用時(shí)可合并在同一個(gè)事務(wù)里)
- support(本身執(zhí)行時(shí)不是事務(wù),被事務(wù)調(diào)用時(shí)可合并在同一個(gè)事務(wù)里)
- not_support(總是非事務(wù)地執(zhí)行,并掛起任何存在的事務(wù))
- mandatory(本身執(zhí)行時(shí)拋出異常,被事務(wù)調(diào)用時(shí)可合并在同一個(gè)事務(wù)里)
- never(總是非事務(wù)地執(zhí)行,如果被其它事務(wù)調(diào)用則拋出異常)
- nest(嵌套事務(wù),本身執(zhí)行時(shí)是事務(wù),被事務(wù)調(diào)用時(shí)也不合并為同一+ 個(gè)事務(wù),但是外層事務(wù)失敗時(shí)內(nèi)層事務(wù)也要回滾)
3.2 隔離級(jí)別
定義了一個(gè)事務(wù)可能受其他并發(fā)事務(wù)影響的程度
1.并發(fā)事務(wù)問(wèn)題:
- 臟讀(一個(gè)事務(wù)讀取了另一個(gè)事務(wù)改寫(xiě)但尚未提交的數(shù)據(jù)時(shí),改寫(xiě)在稍后被回滾了,那么第一個(gè)事務(wù)獲取的數(shù)據(jù)就是無(wú)效的)
- 不可重復(fù)讀
- 幻讀(事務(wù)T1讀取了幾行數(shù)據(jù),接著另一個(gè)并發(fā)事務(wù)T2插入了一些數(shù)據(jù),故在隨后的查詢(xún)中,事務(wù)T1就會(huì)發(fā)現(xiàn)多了一些原本不存在的記錄)
不可重復(fù)讀的重點(diǎn)是同一個(gè)數(shù)據(jù)被修改了,幻讀的重點(diǎn)在于有數(shù)據(jù)新增或者刪除。
從結(jié)果看, 似乎不可重復(fù)讀和幻讀都表現(xiàn)為兩次讀取的結(jié)果不一致。但如果從控制的角度來(lái)看, 兩者的區(qū)別就比較大:
- 對(duì)于前者, 只需要鎖住滿(mǎn)足條件的記錄
- 對(duì)于后者, 要鎖住滿(mǎn)足條件及其相近的記錄
2.隔離級(jí)別
- defaul(使用數(shù)據(jù)庫(kù)默認(rèn)隔離級(jí)別)
- read_uncommit(允許讀取未commit數(shù)據(jù),會(huì)導(dǎo)致上面3種問(wèn)題)
- read_commit(允許讀取commit數(shù)據(jù),僅可避免臟讀)
- repeatable_read(數(shù)據(jù)只可被自身事務(wù)修改,可避免臟讀、不可重復(fù)讀)
- Serializable(完全滿(mǎn)足ACID,通常是鎖表實(shí)現(xiàn))
3.3 是否只讀
如果事務(wù)只對(duì)數(shù)據(jù)庫(kù)進(jìn)行讀操作,則數(shù)據(jù)庫(kù)可以進(jìn)行一些特定的優(yōu)化。通過(guò)將事務(wù)設(shè)置為只讀,你就可以給數(shù)據(jù)庫(kù)一個(gè)機(jī)會(huì),讓它應(yīng)用它認(rèn)為合適的優(yōu)化措施。
3.4 超時(shí)時(shí)間
事務(wù)超時(shí)就是事務(wù)的一個(gè)定時(shí)器,在特定時(shí)間內(nèi)事務(wù)如果沒(méi)有執(zhí)行完畢,那么就會(huì)自動(dòng)回滾,而不是一直等待其結(jié)束。
3.5 回滾規(guī)則
默認(rèn)情況下,事務(wù)只有遇到運(yùn)行期異常時(shí)才會(huì)回滾,而在遇到檢查型異常時(shí)不會(huì)回滾(這一行為與EJB的回滾行為是一致的)
但是你可以聲明事務(wù)在遇到特定的檢查型異常時(shí)像遇到運(yùn)行期異常那樣回滾。同樣,你還可以聲明事務(wù)遇到特定的異常不回滾,即使這些異常是運(yùn)行期異常。
四. spring事務(wù)實(shí)現(xiàn)方式
- 編程式事務(wù)(侵入到業(yè)務(wù)代碼里,但提供了更加詳細(xì)的事務(wù)管理)
- 聲明式事務(wù)(基于A(yíng)OP,不影響業(yè)務(wù)代碼的具體實(shí)現(xiàn))
4.1 編程式事務(wù)
- 使用TransactionTemplate
- 直接使用PlatformTransactionManager
4.2 聲明式事務(wù)
- 每個(gè)Bean都有一個(gè)代理
- 所有Bean共享一個(gè)代理基類(lèi)
- 使用攔截器
- 使用tx標(biāo)簽配置的攔截器
- 全注解
4.3 demo(聲明式事務(wù),全注解方式)
使用@Transactional注解
/**
* 1.propagation 指定事務(wù)的傳播行為
* 默認(rèn)取值為REQUIRED,即使用調(diào)用方法的事務(wù)
* 設(shè)置為REQUIRES_NEW,即使用自己的事務(wù),調(diào)用方法的事務(wù)被掛起
* 2.isolation 指定事務(wù)的隔離級(jí)別,最常用的取值為READ_COMMITTED
* 3.Spring 的聲明式事務(wù)默認(rèn)對(duì)所有運(yùn)行時(shí)異常進(jìn)行回滾,也可以通過(guò)對(duì)應(yīng)的屬性進(jìn)行自行設(shè)置
* 4.readOnly 指定事務(wù)是否為只讀,若這個(gè)事務(wù)只讀取數(shù)據(jù)則設(shè)置為true,可幫助數(shù)據(jù)庫(kù)引擎優(yōu)化事務(wù)
* 5.timeOut 指定強(qiáng)制回滾之前事務(wù)可以占用的時(shí)間
*/
@Transactional(propagation=Propagation.REQUIRES_NEW,
isolation=Isolation.READ_COMMITTED,
noRollbackFor={UserAccountException.class},
readOnly=true, timeout=3)
@Override
public void purchase(String username, String isbn) {
//1.獲取書(shū)的單價(jià)
int price = bookShopDao.findBookPriceByIsbn(isbn);
//2.更新書(shū)的庫(kù)存
bookShopDao.updateBookStock(isbn);
//3.更新用戶(hù)余額
bookShopDao.updateUserAccount(username, price);
}
測(cè)試事務(wù)的傳播行為
@Transactional
@Override
public void checkout(String username, List<String> isbns) {
for(String isbn : isbns) {
bookShopService.purchase(username, isbn);
}
}