常規(guī)的事務(wù)大致有許多種,比如jdbc事務(wù), Hibernate的事務(wù), JpaTransactionObject事務(wù)
關(guān)于他們的對比可以看看事務(wù)比較
我們直接看PlatformTransactionManager
Spring進(jìn)行了統(tǒng)一的抽象,形成了PlatformTransactionManager事務(wù)管理器接口,事務(wù)的提交、回滾等操作全部交給它來實現(xiàn)。
Spring的事務(wù)體系也是在PlatformTransactionManager事務(wù)管理器接口上開展開來的(不管是JPA還是JDBC等都實現(xiàn)自接口 PlatformTransactionManager 如果你添加的是 spring-boot-starter-jdbc 依賴,框架會默認(rèn)注入 DataSourceTransactionManager實例。如果你添加的是 spring-boot-starter-data-jpa 依賴,框架會默認(rèn)注入 JpaTransactionManager 實例。,所以先來了解下PlatformTransactionManager事務(wù)管理器。
事務(wù)功能的總體接口設(shè)計
先來看下三大接口,三個接口功能一句話總的來說事務(wù)管理器基于事務(wù)基礎(chǔ)信息在操作事務(wù)時候?qū)κ聞?wù)狀態(tài)進(jìn)行更新。
PlatformTransactionManager: 事務(wù)管理器TransactionDefinition: 事務(wù)的一些基礎(chǔ)信息,如超時時間、隔離級別、傳播屬性等TransactionStatus: 事務(wù)的一些狀態(tài)信息,如是否是一個新的事務(wù)、是否已被標(biāo)記為回滾
一. 看下PlatformTransactionManager如何來操作事務(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ù)的隔離級別、事務(wù)的傳播屬性、超時時間設(shè)置、是否只讀
- 紅線上方是些常量定義,關(guān)于常量定義(事務(wù)的隔離級別和事務(wù)的傳播屬性等等) 具體事務(wù)常量定義
這里我們要明白的地方:
事務(wù)的隔離級別是數(shù)據(jù)庫本身的事務(wù)功能,我們只是基于對數(shù)據(jù)庫的Connection,對書屋操作做封裝,而事務(wù)的傳播屬性則是Spring自己為我們提供的功能,數(shù)據(jù)庫事務(wù)沒有事務(wù)的傳播屬性這一說法。
DefaultTransactionDefinitio實現(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,如果存在一個事務(wù),則支持當(dāng)前事務(wù)。如果沒有事務(wù)則開啟一個新的事務(wù)。被設(shè)置成這個級別時,會為每一個被調(diào)用的方法創(chuàng)建一個邏輯事務(wù)域。如果前面的方法已經(jīng)創(chuàng)建了事務(wù),那么后面的方法支持當(dāng)前的事務(wù),如果當(dāng)前沒有事務(wù)會重新建立事務(wù),其他請看事務(wù)的傳播屬性 - 事務(wù)的
隔離級別采用底層數(shù)據(jù)庫默認(rèn)的隔離級別 -
超時時間采用底層數(shù)據(jù)庫默認(rèn)的超時時間 -
是否只讀為false
三. 事務(wù)的狀態(tài)信息定義TransactionStatus
先引出Connection連接中的保存點功能:
//創(chuàng)建一個保存點
conn.setSavepoint(name);
//回滾到某個保存點
conn.rollback(savepoint);
//釋放某個保存點
conn.releaseSavepoint(savepoint);
TransactionStatus它繼承了SavepointManager接口,SavepointManager是對事務(wù)中上述保存點功能的封裝,如下:
public interface SavepointManager {
Object createSavepoint() throws TransactionException;
void rollbackToSavepoint(Object savepoint) throws TransactionException;
void releaseSavepoint(Object savepoint) throws TransactionException;
}
Spring利用保存點功能實現(xiàn)了事務(wù)的嵌套功能。后面會詳細(xì)說明。
至于我們說的TransactionStatus本身更多存儲的是事務(wù)的一些狀態(tài)信息:

- 是否是一個新的事物
- 是否有保存點
- 是否已被標(biāo)記為回滾
常用的TransactionStatus接口實現(xiàn)為DefaultTransactionStatus,真正用來操作事務(wù)的:

目前jdbc事務(wù)是通過Connection來實現(xiàn)事務(wù)的,Hibernate是通過它自己定義的Transaction來實現(xiàn)的,所以各家的事務(wù)都不同,所以
Spring只能以O(shè)bject transaction的形式來表示各家的事務(wù),事務(wù)的回滾和提交等操作都會最終委托給上Object transaction來完成。
Object transaction的職責(zé)就是提交回滾事務(wù),這個transaction的選擇可能如下:
- DataSourceTransactionObject
- HibernateTransactionObject
- JpaTransactionObject(之后再詳細(xì)說)
詳細(xì)信息分別如下:
對于DataSourceTransactionObject:
我們使用了dataSource來獲取連接,要想實現(xiàn)事務(wù)功能,必然需要使用Connection,所以它中肯定有一個Connection來執(zhí)行事務(wù)的操作。
DataSourceTransactionObject中有一個ConnectionHolder,它封裝了一個Connection。對于HibernateTransactionObject:
我們使用了hibenrate,此時要想實現(xiàn)事務(wù)功能,必然需要通過hibernate自己定義的Transaction來實現(xiàn)。
HibernateTransactionObject中含有一個SessionHolder,和上面的ConnectionHolder一樣,它封裝了一個Session,有了Session,我們就可以通過Session來產(chǎn)生一個Hibernate的Transaction,從而實現(xiàn)事務(wù)操作。
四. 事務(wù)管理器接口定義PlatformTransactionManager
類圖關(guān)系如下:
重點來說下
- AbstractPlatformTransactionManager
- DataSourceTransactionManager
- HibernateTransactionManager
- JpaTransactionManager(之后詳細(xì)再說)
這就需要來看看事務(wù)管理器的接口,上述的他們都是怎么實現(xiàn)的:
-
1 第一個接口:TransactionStatus getTransaction(TransactionDefinition definition) 根據(jù)事務(wù)定義獲取事務(wù)狀態(tài)
大體內(nèi)容就是先獲取上述說明的Object transaction,判斷當(dāng)前事務(wù)是否已存在,如果存在則進(jìn)行事務(wù)的傳播屬性處理,后面詳細(xì)說明,如果不存在new DefaultTransactionStatus,新創(chuàng)建一個事務(wù),同時使用Object transaction開啟事務(wù)。 分成了幾個過程:
不同的事務(wù)管理器獲取不同的Object transaction
- Spring獲取Object transaction:
DataSourceTransactionManager就是獲取上述的DataSourceTransactionObject
從當(dāng)前線程中獲取綁定的ConnectionHolder,可能為null,如果為null,則會在下一個開
然后我們new 一個DataSourceTransactionObject了,具體過程如下:
啟事務(wù)的過程中,從dataSource中獲取一個Connection,封裝成ConnectionHolder,然后再綁定到當(dāng)前線程 - Spring獲取Object transaction:
構(gòu)建DefaultTransactionStatus,使用Object transaction開啟事務(wù)
DataSourceTransactionManager的DataSourceTransactionObject開啟過程如下:
首先判斷之前的獲取當(dāng)前線程綁定的ConnectionHolder是否為null,如果為null,從dataSource中獲取一個Connection,封裝成ConnectionHolder,然后再綁定到當(dāng)前線程(通過ThreadLocal來實現(xiàn),可以看我別的文章)
因為開啟了一個事務(wù),則必須要關(guān)閉DataSourceTransactionObject中Connection的自動提交,代碼如下(省略一些):
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);
//取消自動提交
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());
}
}
第二個接口:void rollback(TransactionStatus status) 回滾事務(wù)
回滾,則還是利用DefaultTransactionStatus內(nèi)部的Object transaction來執(zhí)行回滾操作
DataSourceTransactionManager就是使用DataSourceTransactionObject中的Connection來進(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);
}
}
第三個接口: void commit(TransactionStatus status) 提交事務(wù)
同理,DataSourceTransactionManager依托內(nèi)部的Connection來完成提交操作
這里對于使用提供一個小demo
比如我們現(xiàn)在涉及到一個付款成功的業(yè)務(wù),涉及到數(shù)據(jù)庫金額更新和數(shù)據(jù)庫訂單狀態(tài)數(shù)據(jù)更新,那么前端發(fā)送一個請求到我們的controller,我們在controller做向上反饋,在service做事務(wù)管理的業(yè)務(wù)操作以及數(shù)據(jù)庫操作
@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;
// 手動開啟事務(wù)初始化
status = transactionManager.getTransaction(new DefaultTransactionDefinition());
//操作
try {
// 數(shù)據(jù)庫操作后(例如業(yè)務(wù)上需先更新金額,再更新訂單信息)
moneyDaoOperation();
DefaultTransactionDefinition
// 操作無異常:提交事務(wù)
transactionManager.commit(status);
log.debug("操作xxxx成功");
return true;
} catch (Exception e) {
log.debug("操作xxxx成功出錯,正在回滾,錯誤信息為:"+e.getMessage());
// 捕獲異常, 事務(wù)回滾
transactionManager.rollback(status);
log.debug("操作xxxx已回滾");
return false;
}
}
}
參考https://blog.csdn.net/luzhensmart/article/details/90167871
``
