HasorDB 事務管理器

2022-01-10 14:41 更新

核心接口方法?

事務管理器是在一個抽象的層面提供主要提供了如下幾個重要的方法。

方法 作用
begin() 開啟事務
commit()、commit(TransactionStatus) 遞交事務
rollBack()、rollBack(TransactionStatus) 回滾事務
hasTransaction() 是否存在處理中的事務
提示
同一個事務管理器可以連續(xù)開啟多個事務,不同事務之間的影響請參考 事務傳播行為

事務棧?

每次調用事務管理器的 begin 方法時就會產(chǎn)生一個新的事務、每產(chǎn)生一個事務就會壓入一個叫做 事務棧 的數(shù)據(jù)結構中。 例如下面代碼,通過 ?TransactionManager? 開啟了三個事務。

DataSource dataSource = DsUtils.dsMySql();
TransactionManager manager = DataSourceManager.getManager(dataSource);

TransactionStatus tranA = manager.begin();
TransactionStatus tranB = manager.begin();
TransactionStatus tranC = manager.begin();

這三個事務在事務棧上的順序如下表示,這是一個標準的 順序棧 結構:

+--------+--------+--------+ <<<< 入棧
| Tran A | Tran B | Tran C |
+--------+--------+--------+ >>>> 出棧

通常情況下針對事務的操作都是按照順序的,這在事務棧上就猶如 入棧 和 出棧 的操作,例如:

DataSource dataSource = DsUtils.dsMySql();
TransactionManager manager = DataSourceManager.getManager(dataSource);

TransactionStatus tranA = manager.begin();
TransactionStatus tranB = manager.begin();
TransactionStatus tranC = manager.begin();
...
manager.commit(tranC);
manager.commit(tranB);
manager.commit(tranA);

HasorDB 有了 事務棧 之后允許操作任意位置的事務,例如:在連續(xù)開啟了三個事務之后一次性遞交三個事務。

DataSource dataSource = DsUtils.dsMySql();
TransactionManager manager = DataSourceManager.getManager(dataSource);

TransactionStatus tranA = manager.begin();
TransactionStatus tranB = manager.begin();
TransactionStatus tranC = manager.begin();
...
manager.commit(tranA);

像這種跨越順序操作事務,HasorDB 會自動將 C 和 B 兩個事務按照它們的順序進行 ?commit ?最后在 ?commit ?它自己。 因此也等價于下面這個方法:

manager.commit(tranC);
manager.commit(tranB);
manager.commit(tranA);

本地事務管理器?

以 ?DataSourceManager.getManager(dataSource);? 方式得到的事務管理器就是本地事務管理器。

本地事務管理器的特點是 數(shù)據(jù)源的事務管理器與當前線程形成一對一綁定,基于這個綁定關系可以達到 本地同步 的目的

獨立事務管理器?

以? new LocalTransactionManager(dataSource);? 方式得到的事務管理器就是獨立事務管理器。

警告
獨立事務管理器是一個不安全的行為,盡量不要使用。

造成不安全的原因在于,事務管理器在維護事務狀態(tài)的時需要經(jīng)常和 ?DataSourceManager ?打交道。 由于 資源同步 機制的存在,當創(chuàng)建多個獨立事務管理器之后容易造成數(shù)據(jù)源管理狀態(tài)混亂的局面。

只是目前設計上的原因,未來版本會逐步解決。

用法?

HasorDB 提供了三種方式使用事務,分別為:

  • 聲明式事務,通過調用 ?TransactionManager ?接口來實現(xiàn)事務控制。
  • 模版事務,通過 ?TransactionTemplate ?接口來實現(xiàn)事務控制。
  • 注解事務,基于 ?@Transaction? 的注解事務控制(開發(fā)中...)

聲明式事務?

啟動和遞交一個事務,例如:

DataSource dataSource = DsUtils.dsMySql();
TransactionManager manager = DataSourceManager.getManager(dataSource);

TransactionStatus tranA = manager.begin();

...

manager.commit(tranA);

或者使用快捷方式

DataSource dataSource = DsUtils.dsMySql();
TransactionManager manager = DataSourceManager.getManager(dataSource);

manager.begin(); // 開啟一個事務

...

manager.commit(); //遞交最近的一個事務

啟動和遞交多個事務,例如:

DataSource dataSource = DsUtils.dsMySql();
TransactionManager manager = DataSourceManager.getManager(dataSource);

TransactionStatus tranA = manager.begin();
TransactionStatus tranB = manager.begin();
TransactionStatus tranC = manager.begin();

...

manager.commit(tranC);
manager.commit(tranB);
manager.commit(tranA);

通過 ?begin ?方法的參數(shù)可以設置事務的 傳播屬性 和 隔離級別

TransactionStatus tranA = manager.begin(
Propagation.REQUIRES_NEW, // 傳播屬性
Isolation.READ_COMMITTED // 隔離級別
);

模版事務?

通常使用事務都會遵循下列邏輯:

try {
manager.begin(behavior, level);

...

manager.commit();
} catch (Throwable e) {
manager.rollBack();
throw e;
}

而模版事務會遵循這個常規(guī)邏輯使其變?yōu)橐粋€更加通用 API 調用方式,下面這段代碼就是模版事務類的實現(xiàn)邏輯:

?類:net.hasor.db.transaction.support.TransactionTemplateManager?

public <T> T execute(TransactionCallback<T> callBack, 
Propagation behavior, Isolation level) throws Throwable {
TransactionStatus tranStatus = null;
try {
tranStatus = this.transactionManager.begin(behavior, level);
return callBack.doTransaction(tranStatus);
} catch (Throwable e) {
if (tranStatus != null) {
tranStatus.setRollback();
}
throw e;
} finally {
if (tranStatus != null && !tranStatus.isCompleted()) {
this.transactionManager.commit(tranStatus);
}
}
}

使用模版事務的方式為:

Object result = template.execute(new TransactionCallback<Object>() {
@Override
public Object doTransaction(TransactionStatus tranStatus) throws Throwable {
...
return null;
}
});

// 使用 Java8 Lambda 語法可以簡化為下面這種
Object result = template.execute(tranStatus -> {
return ...;
});

在事務模版中拋出異常會導致事務回滾,同時異常會繼續(xù)上拋:

try {
Object result = template.execute(new TransactionCallback<Object>() {
public Object doTransaction(TransactionStatus tranStatus) throws Throwable {
throw new Exception("...");
}
});
} catch (Throwable e) {
... run here
}

也可以設置事務狀態(tài)為 ?rollBack ?或 ?readOnly? 也會導致回滾

Object result = template.execute(new TransactionCallback<Object>() {
public Object doTransaction(TransactionStatus tranStatus) throws Throwable {
tranStatus.setReadOnly();
// 或
tranStatus.setRollback();

return ...;
}
});

沒有返回值的模版事務,需要用到 ?TransactionCallbackWithoutResult? 接口。具體用法如下:

template.execute((TransactionCallbackWithoutResult) tranStatus -> {
...
});

注解事務?

(開發(fā)中...)


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號