HasorDB 事務(wù)管理器

2022-01-10 14:41 更新

核心接口方法?

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

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

事務(wù)棧?

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

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

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

這三個(gè)事務(wù)在事務(wù)棧上的順序如下表示,這是一個(gè)標(biāo)準(zhǔn)的 順序棧 結(jié)構(gòu):

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

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

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 有了 事務(wù)棧 之后允許操作任意位置的事務(wù),例如:在連續(xù)開啟了三個(gè)事務(wù)之后一次性遞交三個(gè)事務(wù)。

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

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

像這種跨越順序操作事務(wù),HasorDB 會自動(dòng)將 C 和 B 兩個(gè)事務(wù)按照它們的順序進(jìn)行 ?commit ?最后在 ?commit ?它自己。 因此也等價(jià)于下面這個(gè)方法:

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

本地事務(wù)管理器?

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

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

獨(dú)立事務(wù)管理器?

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

警告
獨(dú)立事務(wù)管理器是一個(gè)不安全的行為,盡量不要使用。

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

只是目前設(shè)計(jì)上的原因,未來版本會逐步解決。

用法?

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

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

聲明式事務(wù)?

啟動(dòng)和遞交一個(gè)事務(wù),例如:

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(); // 開啟一個(gè)事務(wù)

...

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

啟動(dòng)和遞交多個(gè)事務(wù),例如:

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ù)可以設(shè)置事務(wù)的 傳播屬性 和 隔離級別

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

模版事務(wù)?

通常使用事務(wù)都會遵循下列邏輯:

try {
manager.begin(behavior, level);

...

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

而模版事務(wù)會遵循這個(gè)常規(guī)邏輯使其變?yōu)橐粋€(gè)更加通用 API 調(diào)用方式,下面這段代碼就是模版事務(wù)類的實(shí)現(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);
}
}
}

使用模版事務(wù)的方式為:

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 ...;
});

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

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

也可以設(shè)置事務(wù)狀態(tài)為 ?rollBack ?或 ?readOnly? 也會導(dǎo)致回滾

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

return ...;
}
});

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

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

注解事務(wù)?

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


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號