文前说明
作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。
本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。
分析整理的版本为 Ovirt 4.2.3 版本。
1. Ovirt 中的事务管理
- engine 中的 事务管理 是交由 JBoss 容器来完成的,由 JBoss 容器基于 JTA 实现。
- JNDI 命名目录为 java:jboss/TransactionManager。
-
TransactionManagerProducer
类中通过 Java CDI 将TransactionManager
的实现类注入到程序中。
@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 有类似的流程,同样需要设置传播行为和是否打印日志。
网友评论