【Ovirt 筆記】事務相關實現分析與整理
文前說明
作為碼農中的一員,需要不斷的學習,我工作之餘將一些分析總結和學習筆記寫成部落格與大家一起交流,也希望採用這種方式記錄自己的學習之旅。
本文僅供學習交流使用,侵權必刪。
不用於商業目的,轉載請註明出處。
分析整理的版本為 Ovirt 4.2.3 版本。
1. Ovirt 中的事務管理
- engine 中的事務管理 是交由 JBoss 容器來完成的,由 JBoss 容器基於 JTA 實現。
@Produces @Singleton public TransactionManager getTransactionManager() throws NamingException { return (TransactionManager) new InitialContext().lookup("java:jboss/TransactionManager"); }
1.1 事務傳播行為
- engine 中只定義了三種傳播行為,在
TransactionScopeOption
列舉類中進行了定義。
傳播行為 | 說明 |
---|---|
Required | 如果當前沒有事務,就建立一個新事務,如果當前存在事務,就加入該事務,該設定是最常用的設定。 |
Suppress | 支援當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就以非事務執行。 |
RequiresNew | 建立新事務,無論當前存不存在事務,都建立新事務。 |
1.2 事務的支援
- engine 中定義了
TransactionSupport
工具類,用於事務的支援。
靜態方法 | 說明 |
---|---|
findTransactionManager | 獲取事務管理器(單例物件,存在於 CDI 中)。 |
suspend | 掛起當前執行緒關聯的事務。 |
resume | 繼續當前執行緒關聯的事務。 |
current | 返回關聯到當前執行緒的事務。 |
registerRollbackHandler | 回撥介面,以便在事務完成時得到通知從而觸發一些處理工作,如清除快取等。可以通過此介面將回調程式注入到事務中,當事務成功提交後,回撥程式將被啟用。 |
needToRollback | 根據事務狀態判斷是否需要回滾。 |
executeInScope | 執行事務(根據不同的傳播行為)。 |
executeInNewTransaction | 執行傳播行為為 RequiresNew 的事務。 |
setRollbackOnly | 標記當前事務將回滾。 |
1.3 執行事務

執行事務流程
- 其中深藍色箭頭連線表示公共執行。
- 橘黃色箭頭連線表示 RequiresNew 執行。
- 綠色箭頭連線表示 Required 執行。
- 淺藍色箭頭連線表示 Suppress 執行。
public static <T> T executeInScope(TransactionScopeOption scope, TransactionMethod<T> code) { // check if we are already in rollback TransactionManager tm; try { tm = findTransactionManager(); if (needToRollback(tm.getStatus())) { throw new TransactionRolledbackLocalException( "Current transaction is marked for rollback, no further operations are possible or desired"); } } catch (SystemException e) { throw new RuntimeException("Failed to check transaction status - this shouldn't ever happen"); } switch (scope) { case RequiresNew: return executeInNewTransaction(code); case Suppress: return executeInSuppressed(tm, code); case Required: return executeInRequired(tm, code); default: throw new RuntimeException("Undefined Scope: " + scope); } }
1.3.1 excute 方法
protected final void execute() { setCommandStatus(CommandStatus.ACTIVE); getReturnValue().setValid(true); getReturnValue().setIsSynchronous(true); if (shouldPersistCommand()) { persistCommandIfNeeded(); commandCoordinatorUtil.persistCommandAssociatedEntities(getCommandId(), getSubjectEntities()); } executionHandler.addStep(getExecutionContext(), StepEnum.EXECUTING, null); handleCommandStepAndEntities(); try { handleTransactivity(); TransactionSupport.executeInScope(scope, this); } catch (TransactionRolledbackLocalException e) { log.info("Transaction was aborted in '{}'", this.getClass().getName()); // Transaction was aborted - we must sure we compensation for all previous applicative stages of the command compensate(); } finally { try { if (getCommandShouldBeLogged()) { logCommand(); } if (getSucceeded()) { if (getCommandShouldBeLogged()) { logRenamedEntity(); } // only after creating all tasks, we can start polling them (we // don't want // to start polling before all tasks were created, otherwise we // might change // the VM/VmTemplate status to 'Down'/'OK' too soon. startPollingAsyncTasks(); } } finally { if (noAsyncOperations() && !executionHandler.checkIfJobHasTasks(getExecutionContext())) { executionHandler.endJob(getExecutionContext(), getSucceeded()); } } } }
-
handleTransactivity
通過該方法來設定傳播行為。
步驟 | 說明 |
---|---|
第一步 | 通過 Command 的引數設定該傳播行為。 |
第二步 | 根據 Command 是否設定了 @NonTransactiveCommandAttribute ,決定是否採用 Suppress 傳播行為。 |
第三步 | 設定了 @NonTransactiveCommandAttribute,同時又設定了 forceCompensation 屬性為 true,最終執行第一步的傳播行為。 |
-
executeInScope
執行過程丟擲異常,則會執行補償機制。- 可以通過 Command 引數中的 shouldbelogged 屬性設定是否在執行完成 excuete 後列印日誌。
- 也可以在 Command 過程中通過 setCommandShouldBeLogged 方法設定。
- excuete 執行成功後,開始跟輪詢蹤非同步任務。
1.3.2 endAction 方法
-
handleCommandExecutionEnded
判斷是否需要執行 endAction。- 所有的 Command 命令預設執行 endAction。
- 但是如果該 Command 中包含父 Command 引數,則判斷該 Command 的結束程式的屬性(Command 引數中可以設定(預設為 PARENT_MANAGED 不自動執行 endAction))是否為 FLOW_MANAGED 或 COMMAND_MANAGED,如果是則執行,否則不執行。
private boolean handleCommandExecutionEnded() { boolean shouldEndAction = parentHasCallback() ? isEndProcedureApplicableToEndAction() : true; CommandStatus newStatus = isEndSuccessfully() ? CommandStatus.SUCCEEDED : CommandStatus.FAILED; if (getCallback() == null) { setCommandStatus(newStatus); if (!shouldEndAction) { logEndWillBeExecutedByParent(newStatus); } } return shouldEndAction; }
- endAction 與 execute 有類似的流程,同樣需要設定傳播行為和是否列印日誌。