本文主要基於 TCC-Transaction 1.2.3.3 正式版
-
1. 概述
-
2. 資料訪問層
-
2.1 JDBC 事務 DAO
-
2.2 Redis 事務 DAO
-
3. 控制層
-
3.1 檢視未完成的事務串列
-
3.2 重置事務恢復重試次數
-
666. 彩蛋
友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群討論技術和原始碼。
友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群討論技術和原始碼。
友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群討論技術和原始碼。
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 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 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 reset(@PathVariable String domain, String globalTxId, String branchQualifier) {
transactionDao.resetRetryCount(domain,
DatatypeConverter.parseHexBinary(globalTxId),
DatatypeConverter.parseHexBinary(branchQualifier));
return new CommonResponse();
}
UI 介面如下:
666. 彩蛋
可能有人會吐槽運維平臺怎麼做的這麼簡陋。這個不是 TCC-Transaction 一個開源專案存在的問題,其他例如 Dubbo、Disconf 等等都會存在這個情況。
開源作者因為時間關係,更多的精力關註在核心程式碼,所以對運維友好性可能花費的精力較少。
當然,因為是開源的關係,我們可以自己做運維平臺反向的貢獻到這些專案。
胖友,分享一個朋友圈可好?