Github使用指南1.2.x:https://github.com/changmingxie/tcc-transaction/wiki/%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%971.2.x
tcc三个阶段
Try: 尝试执行业务
完成所有业务检查(一致性)
预留必须业务资源(准隔离性)
Confirm: 确认执行业务
真正执行业务
不作任何业务检查
只使用Try阶段预留的业务资源
Confirm操作满足幂等性
Cancel: 取消执行业务
释放Try阶段预留的业务资源
Cancel操作满足幂等性
maven配置
org.mengyun
tcc-transaction-spring
1.2.12
org.mengyun
tcc-transaction-dubbo
1.2.12
org.apache.dubbo
dubbo
zookeeper
org.apache.zookeeper
curator-recipes
org.apache.curator
org.springframework.cloud
spring-cloud-starter-zookeeper-discovery
2.2.1.RELEASE
com.alibaba.cloud
spring-cloud-starter-dubbo
2.2.1.RELEASE
org.apache.dubbo
dubbo
org.apache.dubbo
dubbo
2.7.7
首先需要配置tcc服务与远程tcc服务的config
tcc服务配置
@Configuration
public class TccConfig {
@Bean
public DefaultRecoverConfig defaultRecoverConfig(){
DefaultRecoverConfig defaultRecoverConfig = new DefaultRecoverConfig();
defaultRecoverConfig.setMaxRetryCount(30); //最大重试次数
defaultRecoverConfig.setRecoverDuration(30); //恢复持续时间
defaultRecoverConfig.setCronExpression("0/30 * * * * ?"); //每30秒检查一次是否需要恢复(检查对应的日志表有无需要恢复的数据)//每30秒检查一次是否需要恢复
defaultRecoverConfig.setDelayCancelExceptions(Sets.newHashSet(org.apache.dubbo.remoting.TimeoutException.class));
return defaultRecoverConfig;
}
@Bean("transactionRepository")
public SpringJdbcTransactionRepository springJdbcTransactionRepository(){
SpringJdbcTransactionRepository springJdbcTransactionRepository = new SpringJdbcTransactionRepository();
springJdbcTransactionRepository.setDomain("CONSUMER"); //domain
springJdbcTransactionRepository.setTbSuffix("_CONSUMER"); //配置tcc日志表名称后缀:这里为:tcc_transaction_consumer
//tcc所需分布式事务日志数据源(也可以使用其他数据源框架)
HikariDataSource hikariDataSource = new HikariDataSource();
hikariDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
hikariDataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/tcc?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=CTT");
hikariDataSource.setUsername("root");
hikariDataSource.setPassword("root");
springJdbcTransactionRepository.setDataSource(hikariDataSource);
return springJdbcTransactionRepository;
}
}
远程tcc服务配置,只需要修改以下两处代码,其他配置都相同
springJdbcTransactionRepository.setDomain("PROVIDER");
springJdbcTransactionRepository.setTbSuffix("_PROVIDER"); //配置tcc日志表名称后缀:这里为:tcc_transaction_provider
asyncConfirm = false:是否异步处理confirm阶段,默认false,也就是同步处理
asyncCancel = false:是否异步处理cancel阶段,默认false,也就是同步处理
@Service
public class TccService{
@DubboReference(check = false, retries = 0, timeout = 30000) //dubbo rpc远程过程调用
private TestService testService;
@Override
@Transactional
@Compensable(confirmMethod = "commit", cancelMethod = "rollback", asyncConfirm = false, asyncCancel = false, delayCancelExceptions = {
SocketTimeoutException.class, org.apache.dubbo.remoting.TimeoutException.class})
public void doTry(@UniqueIdentity TransactionContext transactionContext, String accountNo, String to, BigDecimal amount) {
//try阶段
testService.remoteDoTry(transactionContext, accountNo, amount);
}
//如果try阶段成功,commit阶段必须成功,如果commit阶段抛出异常,则会重试commit阶段
@Transactional
public void commit(TransactionContext transactionContext, String accountNo, String to, BigDecimal amount) {
//commit阶段
}
@Transactional
public void rollback(TransactionContext transactionContext, String accountNo, String to, BigDecimal amount) {
//rollback阶段
}
controller调用:
@RestController
public class TestController {
@Autowired
private TccService tccService;
@GetMapping("tcc")
@ResponseBody
public String tcc(String from, String to, BigDecimal amount) throws Exception {
try{
tccService.doTry(null, from, to, amount);
return "success";
} catch (Exception e){
return "fail:" + e.getMessage();
} finally {
System.out.println("success finally");
}
}
}
@Override
@Transactional
@Compensable(confirmMethod = "remoteCommit", cancelMethod = "remoteRollback", asyncConfirm = false, asyncCancel = false, delayCancelExceptions = {
SocketTimeoutException.class, org.apache.dubbo.remoting.TimeoutException.class})
public void remoteDoTry(@UniqueIdentity TransactionContext transactionContext, String accountNo, BigDecimal amount) {
//try阶段
}
//如果try阶段成功,commit阶段必须成功,如果commit阶段抛出异常,则会重试commit阶段
@Transactional
public void remoteCommit(TransactionContext transactionContext, String accountNo, BigDecimal amount) {
//commit阶段
}
@Transactional
public void remoteRollback(TransactionContext transactionContext, String accountNo, BigDecimal amount) {
//rollback阶段
}
TestService接口,注意远程接口上加上@Compensable
注解
@Compensable
void remoteDoTry(TransactionContext transactionContext, String accountNo, BigDecimal amount);
核心代码已经完成,配置启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableDubbo //启动dubbo配置与注解
@EnableAspectJAutoProxy //启动切面类
@ImportResource(locations = {
"classpath:tcc-transaction.xml", "classpath:tcc-transaction-dubbo.xml"}) //加载框架tcc-transaction配置
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application .class, args);
}
}
tcc数据库配置
配置tcc数据库,因为前面配置的数据库名称为tcc,并且tcc服务配置的表后缀为_CONSUMER
,远程tcc服务配置的表后缀为_PROVIDER
,所以在tcc数据库创建两张表,下面是sql脚本
sql脚本,字段都是相同的,不同的只是表名称后缀
CREATE TABLE `tcc_transaction_consumer` (
`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,
`IS_DELETE` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`TRANSACTION_ID`),
UNIQUE KEY `UX_TX_BQ` (`GLOBAL_TX_ID`,`BRANCH_QUALIFIER`)
) ENGINE=InnoDB AUTO_INCREMENT=378 DEFAULT CHARSET=utf8;
CREATE TABLE `tcc_transaction_provider` (
`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,
`IS_DELETE` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`TRANSACTION_ID`),
UNIQUE KEY `UX_TX_BQ` (`GLOBAL_TX_ID`,`BRANCH_QUALIFIER`)
) ENGINE=InnoDB AUTO_INCREMENT=378 DEFAULT CHARSET=utf8;
最后附一张使用apache jmeter压力测试工具的图:测试为100个线程,每个线程吞吐量为10,测试数据是否准确:
调用处理次数1000次没有问题,数据库数据也没有问题 !
至此,tcc分布式事务就完成了,如果还有问题的小伙伴可以留言,看到会第一时间回答,有帮助的朋友点个赞-点个赞-点个赞
,笔芯~