一、实现tcc流程
代码地址:https://gitee.com/ClumsyBird/learn-demo/tree/master/jta/demo2
使用的是 tcc-transaction 中封装的,这里使用的2.0.0版本
tcc-transaction官网地址
tcc-transaction官方git地址
- pom文件引入:
<!-- tcc-transaction的本次demo所用到的jar -->
<dependency>
<groupId>org.mengyun</groupId>
<artifactId>tcc-transaction-spring</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.mengyun</groupId>
<artifactId>tcc-transaction-core</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.mengyun</groupId>
<artifactId>tcc-transaction-api</artifactId>
<version>2.0.0</version>
</dependency>
<!-- 因为tcc-transaction中使用了quartz定时器,将这个引入进来。 也就是他会用定时器去重试调用失败的方法 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
- 建两个springboot项目(也可以建一个项目,用http来模拟多个项目调用)
配置文件如下:(只是做了简单配置,这些配置可以从官网中查看文档进行配置)
- 首先先写一个接口来测试 tcc 流程
这里随便写了一个service方法,在上面加上了@Compensable注解,然后其中有该方法成功时调用某个方法,失败时调用哪个方法。
当有1/0的时候发现调用了失败的方法,去掉这句正常执行的话会进入成功的方法。
- tcc的用途是两个服务之间的,所以用途应该是服务1调用服务2,服务2执行本地事务成功改变了数据,而服务1在执行本地事务的时候失败了,而此时就需要服务1回滚本地事务,并且恢复服务2已经修改了的数据,达到事务中的一致性。
这里使用一个下单流程,客户服务端本地生成订单,调用远程服务的商品端,进行商品数量变更。
4.1 建第一个服务 consumer(客户),其中代码如下
4.2 第二个服务 book(也就是要买书、商品服务),其中代码如下
就是随便处理一些逻辑了,减少商品数量
因为consumer的service中有 1/0,即便第二个服务成功,也需要进行调用cancelMethod再把数据恢复。 - 总结:
5.1 tcc这种模式还是比较繁琐的,故而在一些多个服务强一致性的地方可以使用
5.2 其中的方法需要注意等幂,譬如cancelMethod,如果执行失败,会有线程定时去一直调用
5.3 能够单个服务处理是最好的,否则可以使用jta进行多个数据库间的事务处理,或者使用消息队列来进行多服务通讯,实现最终一致性, tcc感觉只是在一些多服务强一致性关键的地方使用。
5.4 一旦使用分布式事务,那么数据库的事务就没有用处了。数据的事务的ACID都需要人为的用业务代码或者表数据记录等方式去实现,处理会很麻烦。正如《凤凰架构》中所说:某个功能能够进行分布式,并不意味着它就应该进行分布式,强行追求透明的分布式操作,只会自寻苦果。