前言
上一篇文章(https://segmentfault.com/a/11...)我们在springboot2.1.3上集成了lcn5.0.2并简单做了一个lcn模式的demo。LCN官网将源码都给了出来,但是分析源码的部分目前还不是很多,这篇文章主要分析一下LCN模式源码
事务控制原理
分析源码之前,我们首先看一下LCN整体的框架模型:
TX-LCN由两大模块组成, TxClient、TxManager。TxClient作为模块的依赖框架,提供TX-LCN的标准支持,TxManager作为分布式事务的控制放。事务发起方或者参与反都由TxClient端来控制。
原理图:
lcn模式
不难发现,开启处理的地方在拦截器(com.codingapi.txlcn.tc.aspect.TransactionAspect)里面
@Around("lcnTransactionPointcut() && !txcTransactionPointcut()" +
"&& !tccTransactionPointcut() && !txTransactionPointcut()")
public Object runWithLcnTransaction(ProceedingJoinPoint point) throws Throwable {
//将执行分布式事务的方法放在DTXInfo对象里面
DTXInfo dtxInfo = DTXInfo.getFromCache(point);
LcnTransaction lcnTransaction = dtxInfo.getBusinessMethod().getAnnotation(LcnTransaction.class);
dtxInfo.setTransactionType(Transactions.LCN);
dtxInfo.setTransactionPropagation(lcnTransaction.propagation());
//调用方法,正式开启(或继续,这里取决于是否是事务发起方)分布式事务
return dtxLogicWeaver.runTransaction(dtxInfo, point::proceed);
}
走进runTransaction方法,我们可以看到一下内容(伪代码,方便分析)
public class DTXLogicWeaver {
//执行分布式事务的核心方法
public Object runTransaction(){
//1.拿到当前模块的事务上下文和全局事务上下文
DTXLocalContext dtxLocalContext = DTXLocalContext.getOrNew();
TxContext txContext;
// ---------- 保证每个模块在一个DTX下只会有一个TxContext ----------
if (globalContext.hasTxContext()) {
// 有事务上下文的获取父上下文
txContext = globalContext.txContext();
dtxLocalContext.setInGroup(true);//加入事务组
log.debug("Unit[{}] used parent's TxContext[{}].", dtxInfo.getUnitId(), txContext.getGroupId());
} else {
// 没有的开启本地事务上下文
txContext = globalContext.startTx();//下层创建了事务组
}
//2.设置本地事务上下文的一些参数
if (Objects.nonNull(dtxLocalContext.getGroupId())) {
dtxLocalContext.setDestroy(false);
}
dtxLocalContext.setUnitId(dtxInfo.getUnitId());
dtxLocalContext.setGroupId(txContext.getGroupId());//从全局上下文获取
dtxLocalContext.setTransactionType(dtxInfo.getTransactionType());
//3.设置分布式事务参数
TxTransactionInfo info = new TxTransactionInfo();
info.setBusinessCallback(business);//业务执行器(核心)
info.setGroupId(txContext.getGroupId());//从全局上下文获取
info.setUnitId(dtxInfo.getUnitId());
info.setPointMethod(dtxInfo.getBusinessMethod());
info.setPropagation(dtxInfo.getTransactionPropagation());
info.setTransactionInfo(dtxInfo.getTransactionInfo());
info.setTransactionType(dtxInfo.getTransactionType());
info.setTransactionStart(txContext.isDtxStart());
//4.LCN事务处理器
try {
return transactionServiceExecutor.transactionRunning(info);
} finally {
// 线程执行业务完毕清理本地数据
if (dtxLocalContext.isDestroy()) {
// 通知事务执行完毕
synchronized (txContext.getLock()) {
txContext.getLock().notifyAll();
}
// TxContext生命周期是? 和事务组一样(不与具体模块相关的)
if (!dtxLocalContext.isInGroup()) {
globalContext.destroyTx();
}
DTXLocalContext.makeNeverAppeared();
TracingContext.tracing().destroy();
}
log.debug("<---- TxLcn end ---->");
}
}
}
执行业务操作
/**
* 事务业务执行
*
* @param info info
* @return Object
* @throws Throwable Throwable
*/
public Object transactionRunning(TxTransactionInfo info) throws Throwable {
// 1. 获取事务类型
String transactionType = info.getTransactionType();
// 2. 获取事务传播状态
DTXPropagationState propagationState = propagationResolver.resolvePropagationState(info);
// 2.1 如果不参与分布式事务立即终止
if (propagationState.isIgnored()) {
return info.getBusinessCallback().call();
}
// 3. 获取本地分布式事务控制器
DTXLocalControl dtxLocalControl = txLcnBeanHelper.loadDTXLocalControl(transactionType, propagationState);
// 4. 织入事务操作
try {
// 4.1 记录事务类型到事务上下文
Set<String> transactionTypeSet = globalContext.txContext(info.getGroupId()).getTransactionTypes();
transactionTypeSet.add(transactionType);
dtxLocalControl.preBusinessCode(info);
// 4.2 业务执行前
txLogger.txTrace(
info.getGroupId(), info.getUnitId(), "pre business code, unit type: {}", transactionType);
// 4.3 执行业务
Object result = dtxLocalControl.doBusinessCode(info);
// 4.4 业务执行成功
txLogger.txTrace(info.getGroupId(), info.getUnitId(), "business success");
dtxLocalControl.onBusinessCodeSuccess(info, result);
return result;
} catch (TransactionException e) {
txLogger.error(info.getGroupId(), info.getUnitId(), "before business code error");
throw e;
} catch (Throwable e) {
// 4.5 业务执行失败
txLogger.error(info.getGroupId(), info.getUnitId(), Transactions.TAG_TRANSACTION,
"business code error");
dtxLocalControl.onBusinessCodeError(info, e);
throw e;
} finally {
// 4.6 业务执行完毕
dtxLocalControl.postBusinessCode(info);
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。