当前位置:首页 > Java技术 > 终于跑通分布式事务框架tcc-transaction的示例项目

终于跑通分布式事务框架tcc-transaction的示例项目

2022年11月08日 16:01:53Java技术14

1、背景

前段时间在看项目代码的时候,发现有些接口的流程比较长,在各个服务里面都有通过数据库事务保证数据的一致性,但是在上游的controller层并没有对一致性做保证。

网上查了下,还没找到基于Go开源的比较成熟的分布式事务框架。

于是,准备看看之前隔壁部门大佬写的tcc-transaction,这是一个基于tcc思想实现的分布式事务框架。

tcc分别代码Try,Confirm和Cancel。

 

Try: 尝试执行业务

  • 完成所有业务检查(一致性)
  • 预留必须业务资源(准隔离性)

 

Confirm: 确认执行业务

  • 真正执行业务
  • 不作任何业务检查
  • 只使用Try阶段预留的业务资源
  • Confirm操作满足幂等性

 

Cancel: 取消执行业务

  • 释放Try阶段预留的业务资源
  • Cancel操作满足幂等性
  •  

要了解其实现原理,第一步就是跑通项目自带的示例,即tcc-transaction-tutorial-sample部分的代码。

今天主要介绍在跑通tcc-transaction-tutorial-sample过程中遇到的各种坑。

 

 

2、依赖环境

  • Java
  • Maven
  • Git
  • MySQL
  • Redis
  • Zookeeper
  • Intellij IDEA

 

源码地址:https://github.com/changmingxie/tcc-transaction

我自己Fork了一份(配置改动已提交):https://github.com/DMinerJackie/tcc-transaction

 

3、踩坑历程

踩坑准备

第一步:克隆代码

使用"git clone https://github.com/DMinerJackie/tcc-transaction"命令下载代码

 

第二步:导入代码并执行数据库脚本

代码导入Intellij IDEA。

执行tcc-transaction-http-sample/src/main/dbscripts 下的数据库脚本。

 

第三步:修改配置文件

主要修改的是数据库配置参数。拿tcc-transaction-dubbo-sample举例,需要修改的文件有

tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-dubbo-sample/tcc-transaction-dubbo-capital/src/main/resources/tccjdbc.properties

tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-dubbo-sample/tcc-transaction-dubbo-redpacket/src/main/resources/tccjdbc.properties

tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-dubbo-sample/tcc-transaction-dubbo-order/src/main/resources/tccjdbc.properties

三个文件修改后对应配置如下

# 根据具体的MySQL版本使用驱动名称
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
# 换成你连接数据库的地址
tcc.jdbc.url=jdbc:mysql://127.0.0.1:3306/TCC?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
# 换成你需要配置数据库的用户名
jdbc.username=root
# 换成你需要配置数据库的密码
jdbc.password=rootroot

c3p0.initialPoolSize=10
c3p0.minPoolSize=10
c3p0.maxPoolSize=30
c3p0.acquireIncrement=3
c3p0.maxIdleTime=1800
c3p0.checkoutTimeout=30000 

同时修改tcc-transaction-sample-capital、tcc-transaction-sample-redpacket和tcc-transaction-sample-order三个项目中jdbc.proerties文件的数据库连接,修改后配置如下

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/TCC_CAP?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
tcc.jdbc.url=jdbc:mysql://127.0.0.1:3306/TCC?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
jdbc.username=root
jdbc.password=rootroot

c3p0.initialPoolSize=10
c3p0.minPoolSize=10
c3p0.maxPoolSize=30
c3p0.acquireIncrement=3
c3p0.maxIdleTime=1800
c3p0.checkoutTimeout=30000

  

第四步:启动项目

结合项目的README.md文件以及网上的文章了解到如果要跑通示例项目,需要分别启动三个项目。

tcc-transaction提供了两个版本:

  • 基于dubbo通讯的示例版本
  • 基于http通讯的示例版本

这两个版本对于的三个项目分别是

  • tcc-transaction-dubbo-capital(账户资产服务)、 tcc-transaction-dubbo-redpacket(红包服务)、 tcc-transaction-dubbo-order(交易订单服务)
  • tcc-transaction-http-capital(账户资产服务)、 tcc-transaction-http-redpacket(红包服务)、 tcc-transaction-http-order(交易订单服务)

终于跑通分布式事务框架tcc-transaction的示例项目 _ JavaClub全栈架构师技术笔记

其实这两个版本我都跑过,最终成功跑通的只有基于dubbo通讯的示例版本(http版本在最后confirm的时候最是失败,导致最终订单状态为unkown)。

 

以基于dubbo通讯的示例为例

tcc-transaction-dubbo-capital的启动配置如下

终于跑通分布式事务框架tcc-transaction的示例项目 _ JavaClub全栈架构师技术笔记

tcc-transaction-dubbo-redpacket的启动配置如下

终于跑通分布式事务框架tcc-transaction的示例项目 _ JavaClub全栈架构师技术笔记

tcc-transaction-dubbo-order的启动配置如下

终于跑通分布式事务框架tcc-transaction的示例项目 _ JavaClub全栈架构师技术笔记

 

坑1:连接不上zk

启动tcc-transaction-dubbo-capital项目,报错信息如下

[sample-dubbo-capital]2019-08-31 17:48:05,312 INFO [org.apache.zookeeper.ZooKeeper] Initiating client connection, connectString=127.0.0.1:2181 sessionTimeout=30000 watcher=org.I0Itec.zkclient.ZkClient@32c7bb63
[sample-dubbo-capital]2019-08-31 17:48:05,334 INFO [org.apache.zookeeper.ClientCnxn] Opening socket connection to server 127.0.0.1/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
[sample-dubbo-capital]2019-08-31 17:48:05,344 WARN [org.apache.zookeeper.ClientCnxn] Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
java.net.ConnectException: Connection refused
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:361)
at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1081)
[sample-dubbo-capital]2019-08-31 17:48:06,456 INFO [org.apache.zookeeper.ClientCnxn] Opening socket connection to server 127.0.0.1/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
[sample-dubbo-capital]2019-08-31 17:48:06,459 WARN [org.apache.zookeeper.ClientCnxn] Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
java.net.ConnectException: Connection refused
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:361)
at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1081)
[sample-dubbo-capital]2019-08-31 17:48:07,566 INFO [org.apache.zookeeper.ClientCnxn] Opening socket connection to server 127.0.0.1/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
[sample-dubbo-capital]2019-08-31 17:48:07,567 WARN [org.apache.zookeeper.ClientCnxn] Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
java.net.ConnectException: Connection refused

  

从报错信息,一眼就看出是连不上zk即zookeeper。

这个很好理解,因为本地没有安装zk,于是安装并通过"./zkServer.sh start"启动zk

终于跑通分布式事务框架tcc-transaction的示例项目 _ JavaClub全栈架构师技术笔记

 

 

坑2:redis连不上

启动tcc-transaction-dubbo-order报错部分信息如下:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.mengyun.tcctransaction.sample.dubbo.order.service.PlaceOrderServiceImpl org.mengyun.tcctransaction.sample.dubbo.order.web.controller.OrderController.placeOrderService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'placeOrderServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.mengyun.tcctransaction.sample.dubbo.order.service.PaymentServiceImpl org.mengyun.tcctransaction.sample.dubbo.order.service.PlaceOrderServiceImpl.paymentService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'paymentServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.mengyun.tcctransaction.sample.dubbo.capital.api.CapitalTradeOrderService org.mengyun.tcctransaction.sample.dubbo.order.service.PaymentServiceImpl.capitalTradeOrderService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'captialTradeOrderService': Post-processing of FactoryBean's singleton object failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'compensableTransactionAspect' defined in class path resource [tcc-transaction.xml]: Cannot resolve reference to bean 'transactionConfigurator' while setting bean property 'transactionConfigurator'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionConfigurator': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.mengyun.tcctransaction.TransactionRepository org.mengyun.tcctransaction.spring.support.SpringTransactionConfigurator.transactionRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionRepository' defined in file [/Users/jackie/workspace/tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-dubbo-sample/tcc-transaction-dubbo-order/target/tcc-transaction-dubbo-order-1.2.6/WEB-INF/classes/config/spring/local/appcontext-service-tcc.xml]: Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'jedisPool' threw exception; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:526)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:295)
... 60 more

  

 

这个和上面的原因类似,本地没有安装redis,导致无法拿到redis连接。

于是安装redis,并使用"redis-server"启动redis。

终于跑通分布式事务框架tcc-transaction的示例项目 _ JavaClub全栈架构师技术笔记

 

坑3:Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection

三个项目都启动后,可以看到一个商品链接列表页,但是在点击链接后无法跳转,并且报错如下

Type Exception Report
Message Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
Description The server encountered an unexpected condition that prevented it from fulfilling the request.
Exception
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
### The error may exist in URL [jar:file:/Users/jackie/workspace/tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-http-sample/tcc-transaction-http-order/target/tcc-transaction-http-order-1.2.6/WEB-INF/lib/tcc-transaction-sample-order-1.2.6.jar!/config/sqlmap/main/sample-product.xml]
### The error may involve org.mengyun.tcctransaction.sample.order.infrastructure.dao.ProductDao.findByShopId
### The error occurred while executing a query
### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:965)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:844)
javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:829)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106)

Root Cause
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
### The error may exist in URL [jar:file:/Users/jackie/workspace/tcc-transaction/tcc-transaction-tutorial-sample/tcc-transaction-http-sample/tcc-transaction-http-order/target/tcc-transaction-http-order-1.2.6/WEB-INF/lib/tcc-transaction-sample-order-1.2.6.jar!/config/sqlmap/main/sample-product.xml]

  

 

根据错误信息,排查是MySQL版本和数据库驱动版本不匹配。

本地的MySQL版本是"8.0.11 MySQL Community Server - GPL",但是tcc-transaction中对应的驱动版本是

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.33</version>
</dependency>

 

改为

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.11</version>
</dependency>

同时针对高版本,需要在连接的jdbc-url后面加上useSSL=false

 

坑4:Loading class `com.mysql.jdbc.Driver'. This is deprecated

启动tcc-transaction-dubbo-redpacket时,在日志中看到一个警告"Loading class `com.mysql.jdbc.Driver'. This is deprecated"。

通过搜索,发现是因为数据库驱动com.mysql.jdbc.Driver'已经被弃用了,需要使用com.mysql.cj.jdbc.Driver,于是修改jdbc.proerties的配置(具体配置见上面),启动正常。

 

踩完上面的坑后,启动三个项目,完整走完流程,实现了一个基于分布式事务的商品购买行为,具体过程如下图所示

终于跑通分布式事务框架tcc-transaction的示例项目 _ JavaClub全栈架构师技术笔记

 

4、 总结

运行示例项目的过程不算太顺利,主要有一下几个原因吧

  • 本地环境配置和项目提供的不一致,导致走了很多弯路,比如MySQL的版本。
  • 缺少详细的跑示例项目的文档说明。
  • 网上提供的资料比较粗略,也比较陈旧,文中能跑起来的步骤说明已经不适用现在的代码了。

 

所以,在踩完这么多坑总结下,避免后面的人走同样的弯路。

 

 

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。

终于跑通分布式事务框架tcc-transaction的示例项目 _ JavaClub全栈架构师技术笔记

作者:JackieZheng
来源链接:https://www.cnblogs.com/bigdataZJ/p/tcc-transaction-sample.html

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/68519.html

标签: 异常
分享给朋友:

“终于跑通分布式事务框架tcc-transaction的示例项目” 的相关文章

2.Java中Exception和Error的区别

2.Java中Exception和Error的区别

Exception和Error都是继承了Throwable类,在Java中只有Throwable类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型 Error是指在正常情况下,不大可能出现的情况,绝大部分的Error都会导致程序(比...

An exception occurred applying plugin request [id: ‘com.android.application‘]

An exception occurred applying plugin request [id: ‘com.android.application‘]

记一次编译异常 An exception occurred applying plugin request [id: 'com.android.application'] > Failed to apply plugin 'com.android.internal.a...

浅谈 Android  Exception & Throwable 类

浅谈 Android Exception & Throwable 类

一、Throwable 类 概述:java将所有的错误封装为一个对象,其根本父类为Throwable, Throwable有两个子类:Error和Exception。 Error: 这种异常被设计成不被捕获,因为这种异常产生于JVM自身。 Runti...

Uncaught Error: SECURITY_ERR: DOM Exception 18

Question: I get the following error in Ch...

Spring5:@Autowired注解、@Resource注解和@Service注解

什么是注解 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、事物,这么做有两个缺点: 1、如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大;如果按需求分开.xml文件,那么.xml文件又会非常多。总之这将导致配置文件的可读性与...

AndoridStudio--Error:FAILURE: Build failed with an exception.

相信用过Android Studio开发的朋友都知道,Andorid Studio有时候在运行的时候突然出现如下信息: Error:FAILURE: Build failed with an exception. * What went wrong: Execut...

解决项目启动报错--maven依赖冲突

解决项目启动报错--maven依赖冲突

这个问题之前出现过一次,和同事讨论了2天,解决了。后来合 了一下master的分支,问题又出现了,但是忘记了解决方法。现在记录一下免得时间长了又忘记了。 问题描述: Caused by: org.springframework.beans.factory.Unsat...

用Jenkins部署war包到tomcat8报错

用Jenkins部署war包到tomcat8报错"ERROR: Build step failed with exception org.codehaus.cargo.container.ContainerException: Failed to redeploy"的解决办法

一、 Jenkins部署war包到tomcat8 1. 构建结果FAILURE     查看Jenkins控制台,输出的报错的信息如下:   [JENKINS] Archiving /var/lib/jenkins...

org.springframework.beans.factory.BeanCreationException

错误:org.springframework.beans.factory.BeanCreationException: Error creating bean with name '/company/list': Injection of resource fields failed;...

setjmp()、longjmp() Linux Exception Handling/Error Handling、no-local goto

setjmp()、longjmp() Linux Exception Handling/Error Handling、no-local goto

setjmp()、longjmp() Linux Exception Handling/Error Handling、no-local goto 目录 1. 应用场景 2. Use Case Code Analysis 3. 和setjmp、longj...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。