分布式事务 TCC-Transaction 源码分析 —— 运维平台
1. 概述
本文分享 运维平台。TCC-Transaction 提供了相对精简的运维平台,用于查看在《TCC-Transaction 源码分析 —— 事务存储器》提到的事务存储。目前暂时只有两个功能:
- 查看未完成的事务列表
- 重置事务恢复重试次数
运维平台( Maven 项目 tcc-transaction-server
) 整体代码结构如下:
本文自下而上,Dao => Controller => UI 的顺序进行解析实现。
你行好事会因为得到赞赏而愉悦 同理,开源项目贡献者会因为 Star 而更加有动力 为 TCC-Transaction 点赞!传送门
ps:笔者假设你已经阅读过《tcc-transaction 官方文档 —— 使用指南1.2.x》。
2. 数据访问层
org.mengyun.tcctransaction.server.dao.TransactionDao
,事务Dao 接口,实现代码如下:
public interface TransactionDao {
/**
* 获得事务 VO 数组
*
* @param domain 领域
* @param pageNum 第几页
* @param pageSize 分页大小
* @return 事务 VO 数组
*/
List<TransactionVo> findTransactions(String domain, Integer pageNum, int pageSize);
/**
* 获得事务总数量
*
* @param domain 领域
* @return 数量
*/
Integer countOfFindTransactions(String domain);
/**
* 重置事务重试次数
*
* @param domain 领域
* @param globalTxId 全局事务编号
* @param branchQualifier 分支事务编号
* @return 是否重置成功
*/
boolean resetRetryCount(String domain, byte[] globalTxId, byte[] branchQualifier);
}
TCC-Transaction 提供了四种事务存储器,但是目前只支持两种数据访问层的实现:
- JDBC 事务 DAO
- Redis 事务 DAO
2.1 JDBC 事务 DAO
org.mengyun.tcctransaction.server.dao.JdbcTransactionDao
,JDBC 事务 DAO 实现。实现代码如下:
@Repository("jdbcTransactionDao")
public class JdbcTransactionDao implements TransactionDao {
private static final String TABLE_NAME_PREFIX = "TCC_TRANSACTION";
@Autowired
private DataSource dataSource;
/**
* 读取 jdbc-domain-suffix.properties
*/
@Value("#{jdbcDomainSuffix}")
private Properties domainSuffix;
// ... 省略代码
}
-
dataSource
,数据源。配置方式如下: // appcontext-server-dao.xml <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="maxActive" value="50"/> <property name="minIdle" value="5"/> <property name="maxIdle" value="20"/> <property name="initialSize" value="30"/> <property name="logAbandoned" value="true"/> <property name="removeAbandoned" value="true"/> <property name="removeAbandonedTimeout" value="10"/> <property name="maxWait" value="1000"/> <property name="timeBetweenEvictionRunsMillis" value="10000"/> <property name="numTestsPerEvictionRun" value="10"/> <property name="minEvictableIdleTimeMillis" value="10000"/> <property name="validationQuery" value="SELECT NOW() FROM DUAL"/> </bean> // tcc-transaction-server.properties jdbc.url=jdbc:mysql://127.0.0.1:33061/TCC?useUnicode=true&characterEncoding=UTF-8 jdbc.username=root jdbc.password=123456- 在
appcontext-server-dao.xml
,配置数据源 Bean 对象。 - 在
tcc-transaction-server.properties
,配置数据源属性。
- 在
-
domainSuffix
,domian
和 表后缀(suffix
) 的映射关系。配置方式如下: // jdbc-domain-suffix.properties CAPITAL=_CAP ORDER=_ORD REDPACKET=_RED- 键 :domain。
- 值 :suffix。
JdbcTransactionDao 代码实现上比较易懂,点击链接查看,已经添加中文注释。
2.2 Redis 事务 DAO
org.mengyun.tcctransaction.server.dao.RedisTransactionDao
,Redis 事务 DAO。实现代码如下:
@Repository("redisTransactionDao")
public class RedisTransactionDao implements TransactionDao {
/**
* redis pool
*/
@Autowired
private JedisPool jedisPool;
/**
* 序列化
*/
private ObjectSerializer serializer = new JdkSerializationSerializer();
/**
* 读取 redis-domain-key-prefix.properties
*/
@Value("#{redisDomainKeyPrefix}")
private Properties domainKeyPrefix;
}
-
jedisPool
,Redis 连接池。配置方式如下: // appcontext-server-dao.xml <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="300"/> <property name="maxIdle" value="100"/> <property name="minIdle" value="10"/> <property name="maxWaitMillis" value="3000"/> </bean> <bean id="jedisPool" class="redis.clients.jedis.JedisPool"> <constructor-arg index="0" ref="jedisPoolConfig"/> <constructor-arg index="1" value="${redis.host}"/> <constructor-arg index="2" value="${redis.port}" type="int"/> <constructor-arg index="3" value="6000" type="int"/> <constructor-arg index="4" type="java.lang.String"> <null/> </constructor-arg> <constructor-arg index="5" value="${redis.db}" type="int"/> </bean> // tcc-transaction-server.properties redis.host=127.0.0.1 redis.port=6379 redis.password= redis.db=0- 在
appcontext-server-dao.xml
,配置 Redis 连接池 Bean 对象。 - 在
tcc-transaction-server.properties
,配置 Redis 连接池属性。
- 在
-
domainKeyPrefix
,domain 和 Redis Key 前缀(prefix
)的映射。配置方式如下: CAPITAL=TCC:CAP: ORDER=TCC:ORD: REDPACKET=TCC:RED:- 键 :domain。
- 值 :suffix。
RedisTransactionDao 代码实现上比较易懂,点击[链接]https://github.com/YunaiV/tcc-transaction/blob/e54c3e43a2e47a7765bdb18a485860cb31acbb72/tcc-transaction-server/src/main/java/org/mengyun/tcctransaction/server/dao/RedisTransactionDao.java)查看,已经添加中文注释。
3. 控制层
org.mengyun.tcctransaction.server.controller.TransactionController
,事务 Controller。实现代码如下:
@Controller
public class TransactionController {
public static final Integer DEFAULT_PAGE_NUM = 1;
public static final int DEFAULT_PAGE_SIZE = 10;
/**
* 数据访问对象
*/
@Autowired
@Qualifier("jdbcTransactionDao")
private TransactionDao transactionDao;
/**
* 项目访问根目录
*/
@Value("${tcc_domain}")
private String tccDomain;
}
-
transactionDao
,数据访问对象。配置方式如下: // appcontext-server-dao.xml <bean id="transactionDao" class="org.mengyun.tcctransaction.server.dao.JdbcTransactionDao"/>- 目前运维平台只能读取一个数据源,如果你的数据源是多个,需要对运维平台做一定的改造,或启动多个项目。
-
tccDomain
,项目访问根目录。配置方式如下: // tcc-transaction-server.properties tcc_domain=- 一般情况下不用配置,如果你放在 Tomcat 根目录。
3.1 查看未完成的事务列表
调用 TransactionController#manager(...)
方法,查看事务列表。实现代码如下:
@RequestMapping(value = "/management", method = RequestMethod.GET)
public ModelAndView manager() {
return new ModelAndView("manager");
}
@RequestMapping(value = "/management/domain/{domain}", method = RequestMethod.GET)
public ModelAndView manager(@PathVariable String domain) {
return manager(domain, DEFAULT_PAGE_NUM);
}
@RequestMapping(value = "/management/domain/{domain}/pagenum/{pageNum}", method = RequestMethod.GET)
public ModelAndView manager(@PathVariable String domain, @PathVariable Integer pageNum) {
ModelAndView modelAndView = new ModelAndView("manager");
// 获得事务 VO 数组
List<TransactionVo> transactionVos = transactionDao.findTransactions(domain, pageNum, DEFAULT_PAGE_SIZE);
// 获得事务总数量
Integer totalCount = transactionDao.countOfFindTransactions(domain);
// 计算总页数
Integer pages = totalCount / DEFAULT_PAGE_SIZE;
if (totalCount % DEFAULT_PAGE_SIZE > 0) {
pages++;
}
// 返回
modelAndView.addObject("transactionVos", transactionVos);
modelAndView.addObject("pageNum", pageNum);
modelAndView.addObject("pageSize", DEFAULT_PAGE_SIZE);
modelAndView.addObject("pages", pages);
modelAndView.addObject("domain", domain);
modelAndView.addObject("urlWithoutPaging", tccDomain + "/management/domain/" + domain);
return modelAndView;
}
UI 界面如下:
3.2 重置事务恢复重试次数
调用 TransactionController#reset(...)
方法,事务重置重试次数。实现代码如下:
@RequestMapping(value = "/domain/{domain}/retry/reset", method = RequestMethod.PUT)
@ResponseBody
public CommonResponse<Void> reset(@PathVariable String domain, String globalTxId, String branchQualifier) {
transactionDao.resetRetryCount(domain,
DatatypeConverter.parseHexBinary(globalTxId),
DatatypeConverter.parseHexBinary(branchQualifier));
return new CommonResponse<Void>();
}
UI 界面如下:
- 如何安装Windows Phone SDK 7.1 Release Candidate (RC)
- 微信与支付宝回应央行新规:认同央行规范!
- Gulp 工作流中Sass 增量编译功能的探索
- Sass与Compass——回顾
- 苹果就“降速门”致歉;央行批扫码支付不正当竞争;王健林旗下公司遭集体裁员
- 姚期智教授:量子计算是千亿万亿级别的产业,或成为科技创新的引擎
- Powershell中禁止执行脚本解决办法
- 使用AsyncTask异步更新UI界面及原理分析
- 商家为何要做小程序?
- Android中关于dip和px以及转换的总结
- Python介绍
- python案例-用户登录
- 推荐个找代码示例的VS 插件 All-In-One Code Framework Sample Browser
- 明星推出定制AI形象,虚拟形象有何优势
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 20个ES6面试高频问题
- i++和++i傻傻分不清楚?这里给你最清楚的解答
- android APT 使用
- Flutter异步编程async与await的基本使用
- 教大家一个万能PPT图片排版技巧,太赞了!
- 重复读取 HttpServletRequest 中 InputStream 的方法
- 测试面试题集锦(三)| 计算机网络和数据库篇(附答案)
- 关于Scikit-Learn你(也许)不知道的10件事
- 技术天地 | CSS-in-JS:一个充满争议的技术方案
- 安全研究 | 通过域名劫持实现Azure DevOps账户劫持
- 一款针对DLL劫持的恶意DLL生成器
- AuthMatrix:一款针对Web应用和服务的认证安全检测BurpSuite工具
- KITT-Lite:基于Python实现的轻量级命令行渗透测试工具集
- 一次KimSuky攻击事件分析
- OpenCV中如何使用滚动条动态调整参数