事務(wù)管理器是在一個(gè)抽象的層面提供主要提供了如下幾個(gè)重要的方法。
方法 | 作用 |
---|---|
begin() | 開啟事務(wù) |
commit()、commit(TransactionStatus) | 遞交事務(wù) |
rollBack()、rollBack(TransactionStatus) | 回滾事務(wù) |
hasTransaction() | 是否存在處理中的事務(wù) |
提示
同一個(gè)事務(wù)管理器可以連續(xù)開啟多個(gè)事務(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);
以 ?DataSourceManager.getManager(dataSource);
? 方式得到的事務(wù)管理器就是本地事務(wù)管理器。
本地事務(wù)管理器的特點(diǎn)是 數(shù)據(jù)源的事務(wù)管理器與當(dāng)前線程形成一對一綁定,基于這個(gè)綁定關(guān)系可以達(dá)到 本地同步 的目的
以? 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ù),分別為:
TransactionManager
?接口來實(shí)現(xiàn)事務(wù)控制。TransactionTemplate
?接口來實(shí)現(xiàn)事務(wù)控制。@Transaction
? 的注解事務(wù)控制(開發(fā)中...)啟動(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ù)都會遵循下列邏輯:
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 -> {
...
});
(開發(fā)中...)
更多建議: