本文分享 运维平台。TCC-Transaction 提供了相对精简的运维平台,用于查看在《TCC-Transaction 源码分析 —— 事务存储器》提到的事务存储。目前暂时只有两个功能:
运维平台( Maven 项目 tcc-transaction-server
) 整体代码结构如下:
本文自下而上,Dao => Controller => UI 的顺序进行解析实现。
你行好事会因为得到赞赏而愉悦
同理,开源项目贡献者会因为 Star 而更加有动力
为 TCC-Transaction 点赞!传送门
ps:笔者假设你已经阅读过《tcc-transaction 官方文档 —— 使用指南1.2.x》。
org.mengyun.tcctransaction.server.dao.TransactionDao
,事务Dao 接口,实现代码如下:
public
interface TransactionDao {
/**
* 获得事务 VO 数组
*
* @param domain 领域
* @param pageNum 第几页
* @param pageSize 分页大小
* @return 事务 VO 数组
*/
List
/**
* 获得事务总数量
*
* @param domain 领域
* @return 数量
*/
Integer countOfFindTransactions(String domain);
/**
* 重置事务重试次数
*
* @param domain 领域
* @param globalTxId 全局事务编号
* @param branchQualifier 分支事务编号
* @return 是否重置成功
*/
boolean resetRetryCount(String domain, byte[] globalTxId, byte[] branchQualifier);
}
|
TCC-Transaction 提供了四种事务存储器,但是目前只支持两种数据访问层的实现:
org.mengyun.tcctransaction.server.dao.JdbcTransactionDao
,JDBC 事务 DAO 实现。实现代码如下:
"jdbcTransactionDao")
(
public
class JdbcTransactionDao implements TransactionDao {
private
static
final String TABLE_NAME_PREFIX =
"TCC_TRANSACTION";
private DataSource dataSource;
/**
* 读取 jdbc-domain-suffix.properties
*/
"#{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
|
JdbcTransactionDao 代码实现上比较易懂,点击链接查看,已经添加中文注释。
org.mengyun.tcctransaction.server.dao.RedisTransactionDao
,Redis 事务 DAO。实现代码如下:
"redisTransactionDao")
(
public
class RedisTransactionDao implements TransactionDao {
/**
* redis pool
*/
private JedisPool jedisPool;
/**
* 序列化
*/
private ObjectSerializer serializer =
new JdkSerializationSerializer();
/**
* 读取 redis-domain-key-prefix.properties
*/
"#{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:
|
RedisTransactionDao 代码实现上比较易懂,点击[链接]https://github.com/YunaiV/tcc-transaction/blob/e54c3e43a2e47a7765bdb18a485860cb31acbb72/tcc-transaction-server/src/main/java/org/mengyun/tcctransaction/server/dao/RedisTransactionDao.java)查看,已经添加中文注释。
org.mengyun.tcctransaction.server.controller.TransactionController
,事务 Controller。实现代码如下:
public
class TransactionController {
public
static
final Integer DEFAULT_PAGE_NUM =
1;
public
static
final
int DEFAULT_PAGE_SIZE =
10;
/**
* 数据访问对象
*/
"jdbcTransactionDao")
(
private TransactionDao transactionDao;
/**
* 项目访问根目录
*/
"${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=
|
调用 TransactionController#manager(...)
方法,查看事务列表。实现代码如下:
"/management", method = RequestMethod.GET)
(value =
public ModelAndView manager() {
return
new ModelAndView(
"manager");
}
"/management/domain/{domain}", method = RequestMethod.GET)
(value =
public ModelAndView manager(@PathVariable String domain) {
return manager(domain, DEFAULT_PAGE_NUM);
}
"/management/domain/{domain}/pagenum/{pageNum}", method = RequestMethod.GET)
(value =
public ModelAndView manager(@PathVariable String domain, @PathVariable Integer pageNum) {
ModelAndView modelAndView =
new ModelAndView(
"manager");
// 获得事务 VO 数组
List
// 获得事务总数量
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 界面如下:
调用 TransactionController#reset(...)
方法,事务重置重试次数。实现代码如下:
"/domain/{domain}/retry/reset", method = RequestMethod.PUT)
(value =
public CommonResponse
transactionDao.resetRetryCount(domain,
DatatypeConverter.parseHexBinary(globalTxId),
DatatypeConverter.parseHexBinary(branchQualifier));
return
new CommonResponse
}
|
UI 界面如下:
可能有人会吐槽运维平台怎么做的这么简陋。这个不是 TCC-Transaction 一个开源项目存在的问题,其他例如 Dubbo、Disconf 等等都会存在这个情况。
开源作者因为时间关系,更多的精力关注在核心代码,所以对运维友好性可能花费的精力较少。
当然,因为是开源的关系,我们可以自己做运维平台反向的贡献到这些项目。