title: TCC-Transaction 源碼分析 —— 事務(wù)存儲(chǔ)器
date: 2018-02-15
tags:
categories: TCC-Transaction
permalink: TCC-Transaction/transaction-repository
---
摘要: 原創(chuàng)出處 http://www.iocoder.cn/TCC-Transaction/transaction-repository/ 「芋道源碼」歡迎轉(zhuǎn)載,保留摘要,謝謝!
**本文主要基于 TCC-Transaction 1.2.3.3 正式版**
-[1. 概述](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-[2. 序列化](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-[2.1 JDK 序列化實(shí)現(xiàn)](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-[2.2 Kyro 序列化實(shí)現(xiàn)](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-[2.3 JSON 序列化實(shí)現(xiàn)](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-[3. 存儲(chǔ)器](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-[3.1 可緩存的事務(wù)存儲(chǔ)器抽象類](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-[3.2 JDBC 事務(wù)存儲(chǔ)器](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-[3.3 Redis 事務(wù)存儲(chǔ)器](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-[3.4 Zookeeper 事務(wù)存儲(chǔ)器](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-[3.5 File 事務(wù)存儲(chǔ)器](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-[666. 彩蛋](http://www.iocoder.cn/TCC-Transaction/transaction-repository/)
-------

>??????關(guān)注**微信公眾號(hào):【芋道源碼】**有福利:
>1.RocketMQ / MyCAT / Sharding-JDBC **所有**源碼分析文章列表
>2.RocketMQ / MyCAT / Sharding-JDBC **中文注釋源碼 GitHub 地址**
>3.您對(duì)于源碼的疑問每條留言**都**將得到**認(rèn)真**回復(fù)。**甚至不知道如何讀源碼也可以請教噢**。
>4.**新的**源碼解析文章**實(shí)時(shí)**收到通知。**每周更新一篇左右**。
>5.**認(rèn)真的**源碼交流微信群。
---
# 1. 概述
本文分享**事務(wù)存儲(chǔ)器**。主要涉及如下 Maven 項(xiàng)目:
*`tcc-transaction-core`:tcc-transaction 底層實(shí)現(xiàn)。
在 TCC 的過程中,根據(jù)應(yīng)用內(nèi)存中的事務(wù)信息完成整個(gè)事務(wù)流程。But 實(shí)際業(yè)務(wù)場景中,將事務(wù)信息只放在應(yīng)用內(nèi)存中是遠(yuǎn)遠(yuǎn)不夠可靠的。例如:
1.應(yīng)用進(jìn)程異常崩潰,未完成的事務(wù)信息將丟失。
2.應(yīng)用進(jìn)程集群,當(dāng)提供遠(yuǎn)程服務(wù)調(diào)用時(shí),事務(wù)信息需要集群內(nèi)共享。
3.發(fā)起事務(wù)的應(yīng)用需要重啟部署新版本,因?yàn)楦鞣N原因,有未完成的事務(wù)。
因此,TCC-Transaction 將事務(wù)信息添加到內(nèi)存中的同時(shí),會(huì)使用外部存儲(chǔ)進(jìn)行持久化。目前提供四種外部存儲(chǔ):
*JdbcTransactionRepository,JDBC 事務(wù)存儲(chǔ)器
*RedisTransactionRepository,Redis 事務(wù)存儲(chǔ)器
*ZooKeeperTransactionRepository,Zookeeper 事務(wù)存儲(chǔ)器
*FileSystemTransactionRepository,F(xiàn)ile 事務(wù)存儲(chǔ)器
本文涉及到的類關(guān)系如下圖([打開大圖](http://www.iocoder.cn/images/TCC-Transaction/2018_02_15/01.png) ):

>你行好事會(huì)因?yàn)榈玫劫澷p而愉悅
>同理,開源項(xiàng)目貢獻(xiàn)者會(huì)因?yàn)?Star 而更加有動(dòng)力
>為 TCC-Transaction 點(diǎn)贊
ps:筆者假設(shè)你已經(jīng)閱讀過[《tcc-transaction 官方文檔 —— 使用指南1.2.x》](https://github.com/changmingxie/tcc-transaction/wiki/%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%971.2.x)。
# 2. 序列化
在[《TCC-Transaction 源碼分析 —— TCC 實(shí)現(xiàn)》「4. 事務(wù)與參與者」](http://www.iocoder.cn/TCC-Transaction/tcc-core/?self),可以看到 Transaction 是一個(gè)比較復(fù)雜的對(duì)象,內(nèi)嵌 Participant 數(shù)組,而 Participant 本身也是復(fù)雜的對(duì)象,內(nèi)嵌了更多的其他對(duì)象,因此,存儲(chǔ)器在持久化 Transaction 時(shí),需要序列化后才能存儲(chǔ)。
`org.mengyun.tcctransaction.serializer.ObjectSerializer`,對(duì)象序列化**接口**。實(shí)現(xiàn)代碼如下:
```Java
public interface ObjectSerializer {
byte[] serialize(T t);
T deserialize(byte[] bytes);
}
```
目前提供**JDK自帶序列化**和**Kyro序列化**兩種實(shí)現(xiàn)。
## 2.1 JDK 序列化實(shí)現(xiàn)
`org.mengyun.tcctransaction.serializer.JdkSerializationSerializer`,JDK 序列化實(shí)現(xiàn)。比較易懂,點(diǎn)擊[鏈接](https://github.com/changmingxie/tcc-transaction/blob/70130d12004456fd4b97510c210c24502a1b3acb/tcc-transaction-core/src/main/java/org/mengyun/tcctransaction/serializer/JdkSerializationSerializer.java)直接查看。
**TCC-Transaction 使用的默認(rèn)的序列化**。
## 2.2 Kyro 序列化實(shí)現(xiàn)
`org.mengyun.tcctransaction.serializer.KryoTransactionSerializer`,Kyro 序列化實(shí)現(xiàn)。比較易懂,點(diǎn)擊[鏈接](https://github.com/changmingxie/tcc-transaction/blob/70130d12004456fd4b97510c210c24502a1b3acb/tcc-transaction-core/src/main/java/org/mengyun/tcctransaction/serializer/KryoTransactionSerializer.java)直接查看。
## 2.3 JSON 序列化實(shí)現(xiàn)
JDK 和 Kyro 的序列化實(shí)現(xiàn),肉眼無法直觀具體存儲(chǔ)事務(wù)的信息,你可以通過實(shí)現(xiàn) ObjectSerializer 接口,實(shí)現(xiàn)自定義的 JSON 序列化。
# 3. 存儲(chǔ)器
`org.mengyun.tcctransaction.TransactionRepository`,事務(wù)存儲(chǔ)器**接口**。實(shí)現(xiàn)代碼如下:
```Java
public interface TransactionRepository {
/**
* 新增事務(wù)
*
* @paramtransaction事務(wù)
* @return 新增數(shù)量
*/
int create(Transaction transaction);
/**
* 更新事務(wù)
*
* @paramtransaction事務(wù)
* @return 更新數(shù)量
*/
int update(Transaction transaction);
/**
* 刪除事務(wù)
*
* @paramtransaction事務(wù)
* @return 刪除數(shù)量
*/
int delete(Transaction transaction);
/**
* 獲取事務(wù)
*
* @paramxid事務(wù)編號(hào)
* @return 事務(wù)
*/
Transaction findByXid(TransactionXid xid);
/**
* 獲取超過指定時(shí)間的事務(wù)集合
*
* @paramdate指定時(shí)間
* @return 事務(wù)集合
*/
List findAllUnmodifiedSince(Date date);
}
```
不同的存儲(chǔ)器通過實(shí)現(xiàn)該接口,提供事務(wù)的增刪改查功能。
## 3.1 可緩存的事務(wù)存儲(chǔ)器抽象類
`org.mengyun.tcctransaction.repository.CachableTransactionRepository`,**可緩存**的事務(wù)存儲(chǔ)器**抽象類**,實(shí)現(xiàn)增刪改查事務(wù)時(shí),同時(shí)緩存事務(wù)信息。在上面類圖,我們也可以看到 TCC-Transaction 自帶的多種存儲(chǔ)器都繼承該抽象類。
**CachableTransactionRepository 構(gòu)造方法**實(shí)現(xiàn)代碼如下:
```Java
public abstract class CachableTransactionRepository implements TransactionRepository {
/**
* 緩存過期時(shí)間
*/
private int expireDuration = 120;
/**
* 緩存
*/
private Cache transactionXidCompensableTransactionCache;
public CachableTransactionRepository() {
transactionXidCompensableTransactionCache = CacheBuilder.newBuilder().expireAfterAccess(expireDuration, TimeUnit.SECONDS).maximumSize(1000).build();
}
}
```
*使用[Guava Cache](https://github.com/google/guava/wiki/CachesExplained) 內(nèi)存緩存事務(wù)信息,設(shè)置最大緩存?zhèn)€數(shù)為 1000 個(gè),緩存過期時(shí)間為最后訪問時(shí)間 120 秒。
-------
**`#create(...)`**實(shí)現(xiàn)代碼如下:
```Java
@Override
public int create(Transaction transaction) {
int result = doCreate(transaction);
if (result > 0) {
putToCache(transaction);
}
return result;
}
/**
* 添加到緩存
*
* @paramtransaction事務(wù)
*/
protected void putToCache(Transaction transaction) {
transactionXidCompensableTransactionCache.put(transaction.getXid(), transaction);
}
/**
* 新增事務(wù)
*
* @paramtransaction事務(wù)
* @return 新增數(shù)量
*/
protected abstract int doCreate(Transaction transaction);
```
*調(diào)用`#doCreate(...)`方法,新增事務(wù)。新增成功后,調(diào)用`#putToCache(...)`方法,添加事務(wù)到緩存。
*`#doCreate(...)`為抽象方法,子類實(shí)現(xiàn)該方法,提供新增事務(wù)功能。
-------
**`#update(...)`**實(shí)現(xiàn)代碼如下:
```Java
@Override
public int update(Transaction transaction) {
int result = 0;
try {
result = doUpdate(transaction);
if (result > 0) {
putToCache(transaction);
} else {
throw new OptimisticLockException();
}
} finally {
if (result <= 0) { // 更新失敗,移除緩存。下次訪問,從存儲(chǔ)器讀取
removeFromCache(transaction);
}
}
return result;
}
/**
* 移除事務(wù)從緩存
*
* @paramtransaction事務(wù)
*/
protected void removeFromCache(Transaction transaction) {
transactionXidCompensableTransactionCache.invalidate(transaction.getXid());
}
/**
* 更新事務(wù)
*
* @paramtransaction事務(wù)
* @return 更新數(shù)量
*/
protected abstract int doUpdate(Transaction transaction);
```
*調(diào)用`#doUpdate(...)`方法,更新事務(wù)。
*若更新成功后,調(diào)用`#putToCache(...)`方法,添加事務(wù)到緩存。
*若更新失敗后,拋出 OptimisticLockException 異常。有兩種情況會(huì)導(dǎo)致更新失敗:(1) 該事務(wù)已經(jīng)被提交,被刪除;(2) 樂觀鎖更新時(shí),緩存的事務(wù)的版本號(hào)(`Transaction.version`)和存儲(chǔ)器里的事務(wù)的版本號(hào)不同,更新失敗。**為什么**?在[《TCC-Transaction 源碼分析 —— 事務(wù)恢復(fù)》](http://www.iocoder.cn/TCC-Transaction/transaction-recovery/)詳細(xì)解析。更新失敗,意味著緩存已經(jīng)不不一致,調(diào)用`#removeFromCache(...)`方法,移除事務(wù)從緩存中。
*`#doUpdate(...)`為抽象方法,子類實(shí)現(xiàn)該方法,提供更新事務(wù)功能。
-------
**`#delete(...)`**實(shí)現(xiàn)代碼如下:
```Java
@Override
public int delete(Transaction transaction) {
int result;
try {
result = doDelete(transaction);
} finally {
removeFromCache(transaction);
}
return result;
}
/**
* 刪除事務(wù)
*
* @paramtransaction事務(wù)
* @return 刪除數(shù)量
*/
protected abstract int doDelete(Transaction transaction);
```
*調(diào)用`#doDelete(...)`方法,刪除事務(wù)。
*調(diào)用`#removeFromCache(...)`方法,移除事務(wù)從緩存中。
*`#doDelete(...)`為抽象方法,子類實(shí)現(xiàn)該方法,提供刪除事務(wù)功能。
-------
**`#findByXid(...)`**實(shí)現(xiàn)代碼如下:
```Java
@Override
public Transaction findByXid(TransactionXid transactionXid) {
Transaction transaction = findFromCache(transactionXid);
if (transaction == null) {
transaction = doFindOne(transactionXid);
if (transaction != null) {
putToCache(transaction);
}
}
return transaction;
}
/**
* 獲得事務(wù)從緩存中
*
* @paramtransactionXid事務(wù)編號(hào)
* @return 事務(wù)
*/
protected Transaction findFromCache(TransactionXid transactionXid) {
return transactionXidCompensableTransactionCache.getIfPresent(transactionXid);
}
/**
* 查詢事務(wù)
*
* @paramxid事務(wù)編號(hào)
* @return 事務(wù)
*/
protected abstract Transaction doFindOne(Xid xid);
```
*調(diào)用`#findFromCache()`方法,優(yōu)先從緩存中獲取事務(wù)。
*調(diào)用`#doFindOne()`方法,緩存中事務(wù)不存在,從存儲(chǔ)器中獲取。獲取到后,調(diào)用`#putToCache()`方法,添加事務(wù)到緩存中。
*`#doFindOne(...)`為抽象方法,子類實(shí)現(xiàn)該方法,提供查詢事務(wù)功能。
-------
**`#findAllUnmodifiedSince(...)`**實(shí)現(xiàn)代碼如下:
```Java
@Override
public List findAllUnmodifiedSince(Date date) {
List transactions = doFindAllUnmodifiedSince(date);
// 添加到緩存
for (Transaction transaction : transactions) {
putToCache(transaction);
}
return transactions;
}
/**
* 獲取超過指定時(shí)間的事務(wù)集合
*
* @paramdate指定時(shí)間
* @return 事務(wù)集合
*/
protected abstract List doFindAllUnmodifiedSince(Date date);
```
*調(diào)用`#findAllUnmodifiedSince(...)`方法,從存儲(chǔ)器獲取超過指定時(shí)間的事務(wù)集合。調(diào)用`#putToCache(...)`方法,循環(huán)事務(wù)集合添加到緩存。
*`#doFindAllUnmodifiedSince(...)`為抽象方法,子類實(shí)現(xiàn)該方法,提供獲取超過指定時(shí)間的事務(wù)集合功能。
## 3.2 JDBC 事務(wù)存儲(chǔ)器
`org.mengyun.tcctransaction.repository.JdbcTransactionRepository`,JDBC 事務(wù)存儲(chǔ)器,通過 JDBC 驅(qū)動(dòng),將 Transaction 存儲(chǔ)到 MySQL / Oracle / PostgreSQL / SQLServer 等關(guān)系數(shù)據(jù)庫。實(shí)現(xiàn)代碼如下:
```Java
public class JdbcTransactionRepository extends CachableTransactionRepository {
/**
* 領(lǐng)域
*/
private String domain;
/**
* 表后綴
*/
private String tbSuffix;
/**
* 數(shù)據(jù)源
*/
private DataSource dataSource;
/**
* 序列化
*/
private ObjectSerializer serializer = new JdkSerializationSerializer();
}
```
*`domain`,領(lǐng)域,或者也可以稱為模塊名,應(yīng)用名,**用于唯一標(biāo)識(shí)一個(gè)資源**。例如,Maven 模塊`xxx-order`,我們可以配置該屬性為`ORDER`。
*`tbSuffix`,表后綴。默認(rèn)存儲(chǔ)表名為`TCC_TRANSACTION`,配置表名后,為`TCC_TRANSACTION${tbSuffix}`。
*`dataSource`,存儲(chǔ)數(shù)據(jù)的數(shù)據(jù)源。
*`serializer`,序列化。**當(dāng)數(shù)據(jù)庫里已經(jīng)有數(shù)據(jù)的情況下,不要更換別的序列化,否則會(huì)導(dǎo)致反序列化報(bào)錯(cuò)。**建議:TCC-Transaction 存儲(chǔ)時(shí),新增字段,記錄序列化的方式。
表結(jié)構(gòu)如下:
```Java
CREATE TABLE `TCC_TRANSACTION` (
`TRANSACTION_ID` int(11) NOT NULL AUTO_INCREMENT,
`DOMAIN` varchar(100) DEFAULT NULL,
`GLOBAL_TX_ID` varbinary(32) NOT NULL,
`BRANCH_QUALIFIER` varbinary(32) NOT NULL,
`CONTENT` varbinary(8000) DEFAULT NULL,
`STATUS` int(11) DEFAULT NULL,
`TRANSACTION_TYPE` int(11) DEFAULT NULL,
`RETRIED_COUNT` int(11) DEFAULT NULL,
`CREATE_TIME` datetime DEFAULT NULL,
`LAST_UPDATE_TIME` datetime DEFAULT NULL,
`VERSION` int(11) DEFAULT NULL,
PRIMARY KEY (`TRANSACTION_ID`),
UNIQUE KEY `UX_TX_BQ` (`GLOBAL_TX_ID`,`BRANCH_QUALIFIER`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
```
*`TRANSACTION_ID`,僅僅數(shù)據(jù)庫自增,無實(shí)際用途。
*`CONTENT`,Transaction 序列化。
ps:點(diǎn)擊[鏈接](https://github.com/YunaiV/tcc-transaction/blob/c164ff5ab29d31e08bc7061de5bc7403f3e40f1d/tcc-transaction-core/src/main/java/org/mengyun/tcctransaction/repository/JdbcTransactionRepository.java)查看 JdbcTransactionRepository 代碼實(shí)現(xiàn),已經(jīng)添加完整中文注釋。
## 3.3 Redis 事務(wù)存儲(chǔ)器
`org.mengyun.tcctransaction.repository.RedisTransactionRepository`,Redis 事務(wù)存儲(chǔ)器,將 Transaction 存儲(chǔ)到 Redis。實(shí)現(xiàn)代碼如下:
```Java
public class RedisTransactionRepository extends CachableTransactionRepository {
/**
* Jedis Pool
*/
private JedisPool jedisPool;
/**
* key 前綴
*/
private String keyPrefix = "TCC:";
/**
* 序列化
*/
private ObjectSerializer serializer = new JdkSerializationSerializer();
}
```
*`keyPrefix`,key 前綴。類似 JdbcTransactionRepository 的`domain`屬性。
一個(gè)事務(wù)存儲(chǔ)到 Reids,使用 Redis 的數(shù)據(jù)結(jié)構(gòu)為[HASHES](https://redis.io/commands#hash)。
*key : 使用`keyPrefix`+`xid`,實(shí)現(xiàn)代碼如下:
```Java
/**
* 創(chuàng)建事務(wù)的 Redis Key
*
* @paramkeyPrefixkey 前綴
* @paramxid事務(wù)
* @return Redis Key
*/
public static byte[] getRedisKey(String keyPrefix, Xid xid) {
byte[] prefix = keyPrefix.getBytes();
byte[] globalTransactionId = xid.getGlobalTransactionId();
byte[] branchQualifier = xid.getBranchQualifier();
// 拼接 key
byte[] key = new byte[prefix.length + globalTransactionId.length + branchQualifier.length];
System.arraycopy(prefix, 0, key, 0, prefix.length);
System.arraycopy(globalTransactionId, 0, key, prefix.length, globalTransactionId.length);
System.arraycopy(branchQualifier, 0, key, prefix.length + globalTransactionId.length, branchQualifier.length);
return key;
}
```
*HASHES 的 key :使用`version`。
*添加和更新 Transaction 時(shí),使用 Redis[HSETNX](https://redis.io/commands/hsetnx),不存在當(dāng)前版本的值時(shí),進(jìn)行設(shè)置,重而實(shí)現(xiàn)類似樂觀鎖的更新。
*讀取 Transaction 時(shí),使用 Redis[HGETALL](https://redis.io/commands/hgetall),將 Transaction 所有`version`對(duì)應(yīng)的值讀取到內(nèi)存后,取`version`值最大的對(duì)應(yīng)的值。
*HASHES 的 value :調(diào)用`TransactionSerializer#serialize(...)`方法,序列化 Transaction。實(shí)現(xiàn)代碼如下:
```Java
public static byte[] serialize(ObjectSerializer serializer, Transaction transaction) {
Map map = new HashMap();
map.put("GLOBAL_TX_ID", transaction.getXid().getGlobalTransactionId());
map.put("BRANCH_QUALIFIER", transaction.getXid().getBranchQualifier());
map.put("STATUS", transaction.getStatus().getId());
map.put("TRANSACTION_TYPE", transaction.getTransactionType().getId());
map.put("RETRIED_COUNT", transaction.getRetriedCount());
map.put("CREATE_TIME", transaction.getCreateTime());
map.put("LAST_UPDATE_TIME", transaction.getLastUpdateTime());
map.put("VERSION", transaction.getVersion());
// 序列化
map.put("CONTENT", serializer.serialize(transaction));
return serializer.serialize(map);
}
```
*TODO 為什么序列化兩次
在實(shí)現(xiàn)`#doFindAllUnmodifiedSince(date)`方法,無法像數(shù)據(jù)庫使用時(shí)間條件進(jìn)行過濾,因此,加載所有事務(wù)后在內(nèi)存中過濾。實(shí)現(xiàn)代碼如下:
```Java
@Override
protected List doFindAllUnmodifiedSince(Date date) {
// 獲得所有事務(wù)
List allTransactions = doFindAll();
// 過濾時(shí)間
List allUnmodifiedSince = new ArrayList();
for (Transaction transaction : allTransactions) {
if (transaction.getLastUpdateTime().compareTo(date) < 0) {
allUnmodifiedSince.add(transaction);
}
}
return allUnmodifiedSince;
}
```
ps:點(diǎn)擊[鏈接](https://github.com/YunaiV/tcc-transaction/blob/c164ff5ab29d31e08bc7061de5bc7403f3e40f1d/tcc-transaction-core/src/main/java/org/mengyun/tcctransaction/repository/RedisTransactionRepository.java)查看 RedisTransactionRepository 代碼實(shí)現(xiàn),已經(jīng)添加完整中文注釋。
>FROM [《TCC-Transaction 官方文檔 —— 使用指南1.2.x》](https://github.com/changmingxie/tcc-transaction/wiki/%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%971.2.x#%E9%85%8D%E7%BD%AEtcc-transaction)
>使用 RedisTransactionRepository 需要配置 Redis 服務(wù)器如下:
>appendonly yes
>appendfsync always
## 3.4 Zookeeper 事務(wù)存儲(chǔ)器
`org.mengyun.tcctransaction.repository.ZooKeeperTransactionRepository`,Zookeeper 事務(wù)存儲(chǔ)器,將 Transaction 存儲(chǔ)到 Zookeeper。實(shí)現(xiàn)代碼如下:
```Java
public class ZooKeeperTransactionRepository extends CachableTransactionRepository {
/**
* Zookeeper 服務(wù)器地址數(shù)組
*/
private String zkServers;
/**
* Zookeeper 超時(shí)時(shí)間
*/
private int zkTimeout;
/**
* TCC 存儲(chǔ) Zookeeper 根目錄
*/
private String zkRootPath = "/tcc";
/**
* Zookeeper 連接
*/
private volatile ZooKeeper zk;
/**
* 序列化
*/
private ObjectSerializer serializer = new JdkSerializationSerializer();
}
```
*`zkRootPath`,存儲(chǔ) Zookeeper 根目錄,類似 JdbcTransactionRepository 的`domain`屬性。
一個(gè)事務(wù)存儲(chǔ)到 Zookeeper,使用 Zookeeper 的**持久數(shù)據(jù)節(jié)點(diǎn)**。
*path:`${zkRootPath}`+`/`+`${xid}`。實(shí)現(xiàn)代碼如下:
```Java
// ZooKeeperTransactionRepository.java
private String getTxidPath(Xid xid) {
return String.format("%s/%s", zkRootPath, xid);
}
// TransactionXid.java
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("globalTransactionId:").append(UUID.nameUUIDFromBytes(globalTransactionId).toString());
stringBuilder.append(",").append("branchQualifier:").append(UUID.nameUUIDFromBytes(branchQualifier).toString());
return stringBuilder.toString();
}
```
*data:調(diào)用`TransactionSerializer#serialize(...)`方法,序列化 Transaction。
*version:使用 Zookeeper 數(shù)據(jù)節(jié)點(diǎn)自帶版本功能。這里要注意下,Transaction 的版本從 1 開始,而 Zookeeper 數(shù)據(jù)節(jié)點(diǎn)版本從 0 開始。
ps:點(diǎn)擊[鏈接](https://github.com/YunaiV/tcc-transaction/blob/c164ff5ab29d31e08bc7061de5bc7403f3e40f1d/tcc-transaction-core/src/main/java/org/mengyun/tcctransaction/repository/ZooKeeperTransactionRepository.java)查看 ZooKeeperTransactionRepository 代碼實(shí)現(xiàn),已經(jīng)添加完整中文注釋。
另外,在生產(chǎn)上暫時(shí)不建議使用 ZooKeeperTransactionRepository,原因有兩點(diǎn):
*不支持 Zookeeper 安全認(rèn)證。
*使用 Zookeeper 時(shí),未考慮斷網(wǎng)重連等情況。
如果你要使用 Zookeeper 進(jìn)行事務(wù)的存儲(chǔ),可以考慮使用[Apache Curator](https://curator.apache.org/) 操作 Zookeeper,重寫 ZooKeeperTransactionRepository 部分代碼。
## 3.5 File 事務(wù)存儲(chǔ)器
`org.mengyun.tcctransaction.repository.FileSystemTransactionRepository`,F(xiàn)ile 事務(wù)存儲(chǔ)器,將 Transaction 存儲(chǔ)到文件系統(tǒng)。
實(shí)現(xiàn)上和 ZooKeeperTransactionRepository,區(qū)別主要在于不支持樂觀鎖更新。有興趣的同學(xué)點(diǎn)擊[鏈接](https://github.com/YunaiV/tcc-transaction/blob/c164ff5ab29d31e08bc7061de5bc7403f3e40f1d/tcc-transaction-core/src/main/java/org/mengyun/tcctransaction/repository/FileSystemTransactionRepository.java)查看,這里就不拓展開來。
另外,在生產(chǎn)上不建議使用 FileSystemTransactionRepository,因?yàn)椴恢С侄喙?jié)點(diǎn)共享。用分布式存儲(chǔ)掛載文件另說,當(dāng)然還是不建議,因?yàn)椴恢С謽酚^鎖并發(fā)更新。
# 666. 彩蛋
這篇略( 超 )微( 級(jí) )水更,哈哈哈,為[《TCC-Transaction 源碼分析 —— 事務(wù)恢復(fù)》](http://www.iocoder.cn/TCC-Transaction/transaction-recover/?self)做鋪墊啦。
使用 RedisTransactionRepository 和 ZooKeeperTransactionRepository 存儲(chǔ)事務(wù)還是 Get 蠻多點(diǎn)的。

胖友,分享一個(gè)朋友圈可好?