摘要: 原創出處 http://www.iocoder.cn/TCC-Transaction/console/ 「芋道原始碼」歡迎轉載,保留摘要,謝謝!
本文主要基於 TCC-Transaction 1.2.3.3 正式版
???關注**微信公眾號:【芋道原始碼】**有福利:
- RocketMQ / MyCAT / Sharding-JDBC 所有原始碼分析文章列表
- RocketMQ / MyCAT / Sharding-JDBC 中文註釋原始碼 GitHub 地址
- 您對於原始碼的疑問每條留言都將得到認真回覆。甚至不知道如何讀原始碼也可以請教噢。
- 新的原始碼解析文章實時收到通知。每週更新一篇左右。
- 認真的原始碼交流微信群。
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 介面如下:
666. 彩蛋
可能有人會吐槽運維平臺怎麼做的這麼簡陋。這個不是 TCC-Transaction 一個開源專案存在的問題,其他例如 Dubbo、Disconf 等等都會存在這個情況。
開源作者因為時間關係,更多的精力關注在核心程式碼,所以對運維友好性可能花費的精力較少。
當然,因為是開源的關係,我們可以自己做運維平臺反向的貢獻到這些專案。
胖友,分享一個朋友圈可好?