常規(guī)的事務(wù)大致有許多種,比如jdbc事務(wù), Hibernate的事務(wù), JpaTransactionObject事務(wù)
關(guān)于他們的對(duì)比可以看看事務(wù)比較
我們直接看PlatformTransactionManager
Spring進(jìn)行了統(tǒng)一的抽象颠毙,形成了PlatformTransactionManager事務(wù)管理器接口
甫匹,事務(wù)的提交沽甥、回滾等操作
全部交給它來(lái)實(shí)現(xiàn)为严。
Spring的事務(wù)體系也是在PlatformTransactionManager事務(wù)管理器接口
上開(kāi)展開(kāi)來(lái)的(不管是JPA還是JDBC等都實(shí)現(xiàn)自接口 PlatformTransactionManager
如果你添加的是 spring-boot-starter-jdbc
依賴澡绩,框架會(huì)默認(rèn)注入 DataSourceTransactionManager
實(shí)例豹爹。如果你添加的是 spring-boot-starter-data-jpa
依賴责蝠,框架會(huì)默認(rèn)注入 JpaTransactionManager
實(shí)例党巾。萎庭,所以先來(lái)了解下PlatformTransactionManager事務(wù)管理器。
事務(wù)功能的總體接口設(shè)計(jì)
先來(lái)看下三大接口齿拂,三個(gè)接口功能一句話總的來(lái)說(shuō)事務(wù)管理器基于事務(wù)基礎(chǔ)信息在操作事務(wù)時(shí)候?qū)κ聞?wù)狀態(tài)進(jìn)行更新驳规。
PlatformTransactionManager
: 事務(wù)管理器TransactionDefinition
: 事務(wù)的一些基礎(chǔ)信息,如超時(shí)時(shí)間署海、隔離級(jí)別吗购、傳播屬性等TransactionStatus
: 事務(wù)的一些狀態(tài)信息,如是否是一個(gè)新的事務(wù)砸狞、是否已被標(biāo)記為回滾
一. 看下PlatformTransactionManager如何來(lái)操作事務(wù):
public interface PlatformTransactionManager {
//根據(jù)事務(wù)定義TransactionDefinition捻勉,獲取事務(wù)
TransactionStatus getTransaction(TransactionDefinition definition);
//提交事務(wù)
void commit(TransactionStatus status);
//回滾事務(wù)
void rollback(TransactionStatus status);
}
二. 事務(wù)定義接口TransactionDefinition
- 1.事務(wù)的定義包含:事務(wù)的隔離級(jí)別、事務(wù)的傳播屬性刀森、超時(shí)時(shí)間設(shè)置踱启、是否只讀
- 紅線上方是些常量定義,關(guān)于常量定義(事務(wù)的隔離級(jí)別和事務(wù)的傳播屬性等等) 具體事務(wù)常量定義
這里我們要明白的地方:
事務(wù)的隔離級(jí)別是數(shù)據(jù)庫(kù)本身的事務(wù)功能,我們只是基于對(duì)數(shù)據(jù)庫(kù)的Connection撒强,對(duì)書(shū)屋操作做封裝禽捆,而事務(wù)的傳播屬性則是Spring自己為我們提供的功能,數(shù)據(jù)庫(kù)事務(wù)沒(méi)有事務(wù)的傳播屬性這一說(shuō)法飘哨。
DefaultTransactionDefinitio
實(shí)現(xiàn)了該接口(TransactionDefinition):進(jìn)行了一些默認(rèn)的事務(wù)定義
public class DefaultTransactionDefinition implements TransactionDefinition, Serializable {
private int propagationBehavior = PROPAGATION_REQUIRED;
private int isolationLevel = ISOLATION_DEFAULT;
private int timeout = TIMEOUT_DEFAULT;
private boolean readOnly = false;
//略
}
- 事務(wù)的
傳播屬性
為PROPAGATION_REQUIRED
胚想,如果存在一個(gè)事務(wù),則支持當(dāng)前事務(wù)芽隆。如果沒(méi)有事務(wù)則開(kāi)啟一個(gè)新的事務(wù)浊服。被設(shè)置成這個(gè)級(jí)別時(shí),會(huì)為每一個(gè)被調(diào)用的方法創(chuàng)建一個(gè)邏輯事務(wù)域胚吁。如果前面的方法已經(jīng)創(chuàng)建了事務(wù)牙躺,那么后面的方法支持當(dāng)前的事務(wù),如果當(dāng)前沒(méi)有事務(wù)會(huì)重新建立事務(wù),其他請(qǐng)看事務(wù)的傳播屬性 - 事務(wù)的
隔離級(jí)別
采用底層數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別
-
超時(shí)時(shí)間
采用底層數(shù)據(jù)庫(kù)默認(rèn)的超時(shí)時(shí)間
-
是否只讀
為false
三. 事務(wù)的狀態(tài)信息定義TransactionStatus
先引出Connection
連接中的保存點(diǎn)
功能:
//創(chuàng)建一個(gè)保存點(diǎn)
conn.setSavepoint(name);
//回滾到某個(gè)保存點(diǎn)
conn.rollback(savepoint);
//釋放某個(gè)保存點(diǎn)
conn.releaseSavepoint(savepoint);
TransactionStatus它繼承了SavepointManager接口腕扶,SavepointManager是對(duì)事務(wù)中上述保存點(diǎn)功能
的封裝孽拷,如下:
public interface SavepointManager {
Object createSavepoint() throws TransactionException;
void rollbackToSavepoint(Object savepoint) throws TransactionException;
void releaseSavepoint(Object savepoint) throws TransactionException;
}
Spring利用保存點(diǎn)功能實(shí)現(xiàn)了事務(wù)的嵌套功能。后面會(huì)詳細(xì)說(shuō)明半抱。
至于我們說(shuō)的TransactionStatus
本身更多存儲(chǔ)的是事務(wù)的一些狀態(tài)信息:
- 是否是一個(gè)新的事物
- 是否有保存點(diǎn)
- 是否已被標(biāo)記為回滾
常用的TransactionStatus接口實(shí)現(xiàn)為DefaultTransactionStatus脓恕,真正用來(lái)操作事務(wù)的:
目前jdbc事務(wù)是通過(guò)Connection來(lái)實(shí)現(xiàn)事務(wù)的,Hibernate是通過(guò)它自己定義的Transaction來(lái)實(shí)現(xiàn)的窿侈,所以各家的事務(wù)都不同
炼幔,所以
Spring只能以O(shè)bject transaction的形式來(lái)表示各家的事務(wù),事務(wù)的回滾和提交等操作都會(huì)最終委托給上Object transaction
來(lái)完成史简。
Object transaction的職責(zé)就是提交回滾事務(wù)乃秀,這個(gè)transaction的選擇可能如下:
- DataSourceTransactionObject
- HibernateTransactionObject
- JpaTransactionObject(之后再詳細(xì)說(shuō))
詳細(xì)信息分別如下:
對(duì)于DataSourceTransactionObject:
我們使用了dataSource來(lái)獲取連接,要想實(shí)現(xiàn)事務(wù)功能,必然需要使用Connection跺讯,所以它中肯定有一個(gè)Connection來(lái)執(zhí)行事務(wù)的操作枢贿。
DataSourceTransactionObject
中有一個(gè)ConnectionHolder
,它封裝了一個(gè)Connection
抬吟。對(duì)于HibernateTransactionObject:
我們使用了hibenrate,此時(shí)要想實(shí)現(xiàn)事務(wù)功能萨咕,必然需要通過(guò)hibernate自己定義的Transaction來(lái)實(shí)現(xiàn)。
HibernateTransactionObject中含有一個(gè)SessionHolder
火本,和上面的ConnectionHolder一樣,它封裝了一個(gè)Session,有了Session,我們就可以通過(guò)Session來(lái)產(chǎn)生一個(gè)Hibernate的Transaction,從而實(shí)現(xiàn)事務(wù)操作囱淋。
四. 事務(wù)管理器接口定義PlatformTransactionManager
類圖關(guān)系如下:重點(diǎn)來(lái)說(shuō)下
- AbstractPlatformTransactionManager
- DataSourceTransactionManager
- HibernateTransactionManager
- JpaTransactionManager(之后詳細(xì)再說(shuō))
這就需要來(lái)看看事務(wù)管理器的接口建炫,上述的他們都是怎么實(shí)現(xiàn)的:
-
1 第一個(gè)接口:TransactionStatus getTransaction(TransactionDefinition definition) 根據(jù)事務(wù)定義獲取事務(wù)狀態(tài)
大體內(nèi)容就是先獲取上述說(shuō)明的Object transaction,判斷當(dāng)前事務(wù)是否已存在幸海,如果存在則進(jìn)行事務(wù)的傳播屬性處理,后面詳細(xì)說(shuō)明,如果不存在new DefaultTransactionStatus揍魂,新創(chuàng)建一個(gè)事務(wù),同時(shí)使用Object transaction開(kāi)啟事務(wù)棚瘟。 分成了幾個(gè)過(guò)程:
不同的事務(wù)管理器獲取不同的Object transaction
- Spring獲取Object transaction:
DataSourceTransactionManager就是獲取上述的DataSourceTransactionObject
從當(dāng)前線程中獲取綁定的ConnectionHolder现斋,可能為null,如果為null,則會(huì)在下一個(gè)開(kāi)
然后我們new 一個(gè)DataSourceTransactionObject了迷雪,具體過(guò)程如下:
啟事務(wù)的過(guò)程中偎蘸,從dataSource中獲取一個(gè)Connection庄蹋,封裝成ConnectionHolder,然后再綁定到當(dāng)前線程 - Spring獲取Object transaction:
構(gòu)建DefaultTransactionStatus限书,使用Object transaction開(kāi)啟事務(wù)
DataSourceTransactionManager的DataSourceTransactionObject開(kāi)啟過(guò)程如下:
首先判斷之前的獲取當(dāng)前線程綁定的ConnectionHolder是否為null,如果為null章咧,從dataSource中獲取一個(gè)Connection倦西,封裝成ConnectionHolder
,然后再綁定到當(dāng)前線程(通過(guò)ThreadLocal來(lái)實(shí)現(xiàn)赁严,可以看我別的文章)
因?yàn)?strong>開(kāi)啟了一個(gè)事務(wù)扰柠,則必須要關(guān)閉DataSourceTransactionObject中Connection的自動(dòng)提交,代碼如下(省略一些):
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
//如果ConnectionHolder是否為null误澳,從新獲取
if (txObject.getConnectionHolder() == null ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.dataSource.getConnection();
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
con = txObject.getConnectionHolder().getConnection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
//取消自動(dòng)提交
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
txObject.getConnectionHolder().setTransactionActive(true);
//如果是新增的ConnectionHolder耻矮,則綁定到當(dāng)前線程
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}
第二個(gè)接口:void rollback(TransactionStatus status) 回滾事務(wù)
回滾,則還是利用DefaultTransactionStatus內(nèi)部的Object transaction來(lái)執(zhí)行回滾操作
DataSourceTransactionManager就是使用DataSourceTransactionObject中的Connection來(lái)進(jìn)行回滾操作
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
try {
con.rollback();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}
第三個(gè)接口: void commit(TransactionStatus status) 提交事務(wù)
同理忆谓,DataSourceTransactionManager依托內(nèi)部的Connection來(lái)完成提交操作
這里對(duì)于使用提供一個(gè)小demo
比如我們現(xiàn)在涉及到一個(gè)付款成功的業(yè)務(wù),涉及到數(shù)據(jù)庫(kù)金額更新和數(shù)據(jù)庫(kù)訂單狀態(tài)數(shù)據(jù)更新,那么前端發(fā)送一個(gè)請(qǐng)求到我們的controller,我們?cè)赾ontroller做向上反饋,在service做事務(wù)管理的業(yè)務(wù)操作以及數(shù)據(jù)庫(kù)操作
@PostMapping("moneyOperation")
public String moneyOperation() {
if (transactionOperation.moneyOperation()) {
return "付款成功";
}
else {
return "付款失旕勺啊!";
}
}
/**
* @description: money相關(guān)事務(wù)demo
* @author: zyh
* @create: 2021-06-23 14:06
**/
@Service
@Slf4j
@RequiredArgsConstructor
public class TransactionOperation {
private final PlatformTransactionManager transactionManager;
public boolean moneyOperation() {
TransactionStatus status;
// 手動(dòng)開(kāi)啟事務(wù)初始化
status = transactionManager.getTransaction(new DefaultTransactionDefinition());
//操作
try {
// 數(shù)據(jù)庫(kù)操作后(例如業(yè)務(wù)上需先更新金額,再更新訂單信息)
moneyDaoOperation();
DefaultTransactionDefinition
// 操作無(wú)異常:提交事務(wù)
transactionManager.commit(status);
log.debug("操作xxxx成功");
return true;
} catch (Exception e) {
log.debug("操作xxxx成功出錯(cuò),正在回滾,錯(cuò)誤信息為:"+e.getMessage());
// 捕獲異常, 事務(wù)回滾
transactionManager.rollback(status);
log.debug("操作xxxx已回滾");
return false;
}
}
}
參考https://blog.csdn.net/luzhensmart/article/details/90167871
``