前言
先前在《阿里开源分布式事务组件 seata :demo 环境搭建以及运行流程简析》 这篇文章中已经提到过:
seata 客户端在处理事务逻辑的时候,实际上采用模板模式,委托给了 TransactionalTemplate 类去执行标准的事务处理流程,如下代码所示:
public Object execute(TransactionalExecutor business) throws Throwable {
// 1. get or create a transaction
GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
// 1.1 get transactionInfo
TransactionInfo txInfo = business.getTransactionInfo();
if (txInfo == null) {
throw new ShouldNeverHappenException("transactionInfo does not exist");
}
try {
// 2. begin transaction
beginTransaction(txInfo, tx);
Object rs = null;
try {
// Do Your Business
rs = business.execute();
} catch (Throwable ex) {
// 3.the needed business exception to rollback.
completeTransactionAfterThrowing(txInfo,tx,ex);
throw ex;
}
// 4. everything is fine, commit.
commitTransaction(tx);
return rs;
} finally {
//5. clear
triggerAfterCompletion();
cleanUp();
}
}
在客户端的事务处理流程中,流程比较清晰,处理流程也不复杂,除了客户端自身采用了一些机制,其实 seata 把比较“重”的逻辑都放在了 server 端。
比如说,开启一个全局事务时,事务 id 如何生成,事务的信息如何存储,这些是不需要客户端的关心的。
当我们使用标准的 JDBC 规范来处理单库数据库事务时,代码几乎都和下面是同一个模板:
conn.setAutocommit(false);
try {
// 在这里使用 connection 进行 sql 操作;
conn.xxxxxx
//如果一切正常,则直接进行提交
conn.commit();
} catch (Exception e) {
conn.rollback();
}
虽然分布式事务和单机事务在“分布式” 和 “单机” 上区别很大,但在 “事务” 这个角度,却是相同的。
我们可以看到 seata 客户端的事务处理逻辑,跟单机事务的处理逻辑大同小异。
有差异的两个地方主要是:
seata 中的全局事务如果提交失败,是不需要进行回滚,会有别的补救措施。
针对事务主体执行期间发生的异常,是不一定要回滚的,遇到有些异常可以直接提交,而有时候又可以直接忽略,不过这块跟具体场景有关系,默认出现了异