springcloud+eureka整合seata-tcc模式(下)

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
EMR Serverless StarRocks,5000CU*H 48000GB*H
应用型负载均衡 ALB,每月750个小时 15LCU
简介: springcloud+eureka整合seata-tcc模式

2.两阶段提交,我们以账户服务为例,接口定义如下:

@FeignClient(value = "account-server")
@LocalTCC
public interface AccountApi {
    /**
     * 扣减账户余额
     * @param actionContext save xid
     * @param userId 用户id
     * @param money 金额
     * @return
     */
    @TwoPhaseBusinessAction(name = "accountApi", commitMethod = "commit", rollbackMethod = "rollback")
    @RequestMapping("/account/decrease")
    boolean prepare(@RequestBody BusinessActionContext actionContext, @RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money);
    /**
     * Commit boolean.
     *
     * @param actionContext save xid
     * @return the boolean
     */
    @RequestMapping("/account/commit")
    boolean commit(@RequestBody BusinessActionContext actionContext);
    /**
     * Rollback boolean.
     *
     * @param actionContext save xid
     * @return the boolean
     */
    @RequestMapping("/account/rollback")
    boolean rollback(@RequestBody BusinessActionContext actionContext);
}

整个接口的注解有2个,一个是FeignClient,因为服务间采用Feign进行通信,不多说明。第二个就是@LocalTCC,这个就标注了这是一个TCC的分支事务接口类,里面定义了TCC要求的3个方法。尤其强调的是,prepare方法上面要加注解@TwoPhaseBusinessAction,注解里面要指定提交和回滚的方法。

这个接口作为feign客户端,请求发送到了账户服务,账户服务接到对应的请求后分别进行处理。


3.账户服务中controller接到请求后,调用对应的service进行处理,代码如下:

@Service("accountServiceImpl")
public class AccountServiceImpl implements AccountService{
    private static final Logger LOGGER = LoggerFactory.getLogger(AccountServiceImpl.class);
    private Map<String, Statement> statementMap = new ConcurrentHashMap<>(100);
    private Map<String, Connection> connectionMap = new ConcurrentHashMap<>(100);
    @Resource
    private DataSource hikariDataSource;
    @Override
    public boolean decrease(String xid, Long userId, BigDecimal payAmount) {
        LOGGER.info("commit, xid:{}", xid);
        LOGGER.info("------->尝试扣减账户开始account");
        //模拟超时异常,全局事务回滚
        /*try {
            Thread.sleep(30*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        try {
            //尝试扣减账户金额,事务不提交
            Connection connection = hikariDataSource.getConnection();
            connection.setAutoCommit(false);
            String sql = "UPDATE account SET balance = balance - ?,used = used + ? where user_id = ?";
            PreparedStatement stmt = connection.prepareStatement(sql);
            stmt.setBigDecimal(1, payAmount);
            stmt.setBigDecimal(2, payAmount);
            stmt.setLong(3, userId);
            stmt.executeUpdate();
            statementMap.put(xid, stmt);
            connectionMap.put(xid, connection);
        } catch (Exception e) {
            LOGGER.error("decrease parepare failure:", e);
            return false;
        }
        LOGGER.info("------->尝试扣减账户结束account");
        return true;
    }
    public boolean commit(String xid){
        LOGGER.info("扣减账户金额, commit, xid:{}", xid);
        PreparedStatement statement = (PreparedStatement) statementMap.get(xid);
        Connection connection = connectionMap.get(xid);
        try {
            if (null != connection){
                connection.commit();
            }
        } catch (SQLException e) {
            LOGGER.error("扣减账户失败:", e);
            return false;
        }finally {
            try {
                statementMap.remove(xid);
                connectionMap.remove(xid);
                if (null != statement){
                    statement.close();
                }
                if (null != connection){
                    connection.close();
                }
            } catch (SQLException e) {
                LOGGER.error("扣减账户提交事务后关闭连接池失败:", e);
            }
        }
        return true;
    }
    public boolean rollback(String xid){
        LOGGER.info("扣减账户金额, rollback, xid:{}", xid);
        PreparedStatement statement = (PreparedStatement) statementMap.get(xid);
        Connection connection = connectionMap.get(xid);
        try {
            connection.rollback();
        } catch (SQLException e) {
            return false;
        }finally {
            try {
                if (null != statement){
                    statement.close();
                }
                if (null != connection){
                    connection.close();
                }
                statementMap.remove(xid);
                connectionMap.remove(xid);
            } catch (SQLException e) {
                LOGGER.error("扣减账户回滚事务后关闭连接池失败:", e);
            }
        }
        return true;
    }
}

从上面的代码中我们可以看到,我们使用了jdbc进行了事务管理,prepare方法缓存了Statement和Connection,commit和rollback方法进行事务的提交和回滚,然后释放连接。


实验结果


启动eureka server,seata server,然后启动上面3个服务。

运行之前,我们先看一下数据库的数据,seata_order库中orders表没有数据,seata_pay库中account表和seata_storage库中storage表数据如下图:

微信图片_20221212144730.png

微信图片_20221212144749.png

1.模拟commit事务

服务启动后,我们用postman发一个post请求,请求url:http://localhost:8180/order/create,请求参数:

{
  "userId":1,
  "productId":1,
  "count":1,
  "money":1,
  "payAmount":50
}

请求成功后,我们查看上面3张表的数据,如下图:

微信图片_20221212144825.png

微信图片_20221212144838.png

微信图片_20221212144853.png

可以看到,数据已经提交成功了。这时我们查看一下order-server日志:

2020-08-23 10:13:00.187  INFO 638408 --- [nio-8180-exec-1] io.seata.tm.TransactionManagerHolder     : TransactionManager Singleton io.seata.tm.DefaultTransactionManager@2501a5fc
2020-08-23 10:13:00.207  INFO 638408 --- [nio-8180-exec-1] i.seata.tm.api.DefaultGlobalTransaction  : Begin new global transaction [192.168.59.132:8091:41466478607220736]
2020-08-23 10:13:00.212  INFO 638408 --- [nio-8180-exec-1] i.seata.sample.service.OrderServiceImpl  : ------->交易开始
2020-08-23 10:13:00.232  INFO 638408 --- [nio-8180-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-08-23 10:13:00.431  INFO 638408 --- [nio-8180-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-08-23 10:13:00.445  INFO 638408 --- [nio-8180-exec-1] i.seata.sample.service.OrderServiceImpl  : ------->扣减库存开始storage中
2020-08-23 10:13:00.645  INFO 638408 --- [nio-8180-exec-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: storage-server.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-08-23 10:13:00.899  INFO 638408 --- [nio-8180-exec-1] c.n.u.concurrent.ShutdownEnabledTimer    : Shutdown hook installed for: NFLoadBalancer-PingTimer-storage-server
2020-08-23 10:13:00.900  INFO 638408 --- [nio-8180-exec-1] c.netflix.loadbalancer.BaseLoadBalancer  : Client: storage-server instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=storage-server,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2020-08-23 10:13:00.906  INFO 638408 --- [nio-8180-exec-1] c.n.l.DynamicServerListLoadBalancer      : Using serverListUpdater PollingServerListUpdater
2020-08-23 10:13:00.938  INFO 638408 --- [nio-8180-exec-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: storage-server.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-08-23 10:13:00.941  INFO 638408 --- [nio-8180-exec-1] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client storage-server initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=storage-server,current list of Servers=[10.192.86.60:8182],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;  Instance count:1;  Active connections count: 0;  Circuit breaker tripped count: 0;  Active connections per server: 0.0;]
},Server stats: [[Server:10.192.86.60:8182;  Zone:defaultZone;  Total Requests:0;  Successive connection failure:0;  Total blackout seconds:0;  Last connection made:Thu Jan 01 08:00:00 CST 1970;  First connection made: Thu Jan 01 08:00:00 CST 1970;  Active Connections:0;  total failure count in last (1000) msecs:0;  average resp time:0.0;  90 percentile resp time:0.0;  95 percentile resp time:0.0;  min resp time:0.0;  max resp time:0.0;  stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@50d8d3a7
2020-08-23 10:13:01.165  INFO 638408 --- [nio-8180-exec-1] i.seata.sample.service.OrderServiceImpl  : ------->扣减库存结束storage中
2020-08-23 10:13:01.165  INFO 638408 --- [nio-8180-exec-1] i.seata.sample.service.OrderServiceImpl  : ------->扣减账户开始account中
2020-08-23 10:13:01.211  INFO 638408 --- [nio-8180-exec-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: account-server.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-08-23 10:13:01.212  INFO 638408 --- [nio-8180-exec-1] c.n.u.concurrent.ShutdownEnabledTimer    : Shutdown hook installed for: NFLoadBalancer-PingTimer-account-server
2020-08-23 10:13:01.212  INFO 638408 --- [nio-8180-exec-1] c.netflix.loadbalancer.BaseLoadBalancer  : Client: account-server instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=account-server,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2020-08-23 10:13:01.213  INFO 638408 --- [nio-8180-exec-1] c.n.l.DynamicServerListLoadBalancer      : Using serverListUpdater PollingServerListUpdater
2020-08-23 10:13:01.214  INFO 638408 --- [nio-8180-exec-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: account-server.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-08-23 10:13:01.215  INFO 638408 --- [nio-8180-exec-1] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client account-server initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=account-server,current list of Servers=[10.192.86.60:8181],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;  Instance count:1;  Active connections count: 0;  Circuit breaker tripped count: 0;  Active connections per server: 0.0;]
},Server stats: [[Server:10.192.86.60:8181;  Zone:defaultZone;  Total Requests:0;  Successive connection failure:0;  Total blackout seconds:0;  Last connection made:Thu Jan 01 08:00:00 CST 1970;  First connection made: Thu Jan 01 08:00:00 CST 1970;  Active Connections:0;  total failure count in last (1000) msecs:0;  average resp time:0.0;  90 percentile resp time:0.0;  95 percentile resp time:0.0;  min resp time:0.0;  max resp time:0.0;  stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@7145f1b9
2020-08-23 10:13:01.640  INFO 638408 --- [nio-8180-exec-1] i.seata.sample.service.OrderServiceImpl  : ------->扣减账户结束account中true
2020-08-23 10:13:01.641  INFO 638408 --- [nio-8180-exec-1] i.seata.sample.service.OrderServiceImpl  : ------->交易结束
2020-08-23 10:13:01.648  INFO 638408 --- [ch_RMROLE_1_1_8] i.s.c.r.p.c.RmBranchCommitProcessor      : rm client handle branch commit process:xid=192.168.59.132:8091:41466478607220736,branchId=41466478707884032,branchType=TCC,resourceId=orderApi,applicationData={"actionContext":{"sys::rollback":"rollback","sys::commit":"commit","action-start-time":1598321580213,"host-name":"10.192.254.57","sys::prepare":"saveOrder","actionName":"orderApi"}}
2020-08-23 10:13:01.651  INFO 638408 --- [ch_RMROLE_1_1_8] io.seata.rm.AbstractRMHandler            : Branch committing: 192.168.59.132:8091:41466478607220736 41466478707884032 orderApi {"actionContext":{"sys::rollback":"rollback","sys::commit":"commit","action-start-time":1598321580213,"host-name":"10.192.254.57","sys::prepare":"saveOrder","actionName":"orderApi"}}
2020-08-23 10:13:01.652  INFO 638408 --- [ch_RMROLE_1_1_8] io.seata.sample.service.OrderSaveImpl    : 保存订单, commit, xid:192.168.59.132:8091:41466478607220736
2020-08-23 10:13:01.657  INFO 638408 --- [ch_RMROLE_1_1_8] io.seata.rm.AbstractResourceManager      : TCC resource commit result : true, xid: 192.168.59.132:8091:41466478607220736, branchId: 41466478707884032, resourceId: orderApi
2020-08-23 10:13:01.659  INFO 638408 --- [ch_RMROLE_1_1_8] io.seata.rm.AbstractRMHandler            : Branch commit result: PhaseTwo_Committed
2020-08-23 10:13:01.664  INFO 638408 --- [ch_RMROLE_1_2_8] i.s.c.r.p.c.RmBranchCommitProcessor      : rm client handle branch commit process:xid=192.168.59.132:8091:41466478607220736,branchId=41466479647408128,branchType=TCC,resourceId=storageApi,applicationData={"actionContext":{"sys::rollback":"rollback","sys::commit":"commit","action-start-time":1598321580446,"host-name":"10.192.254.57","sys::prepare":"decrease","actionName":"storageApi"}}
2020-08-23 10:13:01.664  INFO 638408 --- [ch_RMROLE_1_2_8] io.seata.rm.AbstractRMHandler            : Branch committing: 192.168.59.132:8091:41466478607220736 41466479647408128 storageApi {"actionContext":{"sys::rollback":"rollback","sys::commit":"commit","action-start-time":1598321580446,"host-name":"10.192.254.57","sys::prepare":"decrease","actionName":"storageApi"}}
2020-08-23 10:13:01.677  INFO 638408 --- [ch_RMROLE_1_2_8] io.seata.rm.AbstractResourceManager      : TCC resource commit result : true, xid: 192.168.59.132:8091:41466478607220736, branchId: 41466479647408128, resourceId: storageApi
2020-08-23 10:13:01.677  INFO 638408 --- [ch_RMROLE_1_2_8] io.seata.rm.AbstractRMHandler            : Branch commit result: PhaseTwo_Committed
2020-08-23 10:13:01.680  INFO 638408 --- [ch_RMROLE_1_3_8] i.s.c.r.p.c.RmBranchCommitProcessor      : rm client handle branch commit process:xid=192.168.59.132:8091:41466478607220736,branchId=41466482671501312,branchType=TCC,resourceId=accountApi,applicationData={"actionContext":{"sys::rollback":"rollback","sys::commit":"commit","action-start-time":1598321581166,"host-name":"10.192.254.57","sys::prepare":"prepare","actionName":"accountApi"}}
2020-08-23 10:13:01.680  INFO 638408 --- [ch_RMROLE_1_3_8] io.seata.rm.AbstractRMHandler            : Branch committing: 192.168.59.132:8091:41466478607220736 41466482671501312 accountApi {"actionContext":{"sys::rollback":"rollback","sys::commit":"commit","action-start-time":1598321581166,"host-name":"10.192.254.57","sys::prepare":"prepare","actionName":"accountApi"}}
2020-08-23 10:13:01.695  INFO 638408 --- [ch_RMROLE_1_3_8] io.seata.rm.AbstractResourceManager      : TCC resource commit result : true, xid: 192.168.59.132:8091:41466478607220736, branchId: 41466482671501312, resourceId: accountApi
2020-08-23 10:13:01.695  INFO 638408 --- [ch_RMROLE_1_3_8] io.seata.rm.AbstractRMHandler            : Branch commit result: PhaseTwo_Committed
2020-08-23 10:13:01.702  INFO 638408 --- [nio-8180-exec-1] i.seata.tm.api.DefaultGlobalTransaction  : [192.168.59.132:8091:41466478607220736] commit status: Committed
2020-08-23 10:13:01.911  INFO 638408 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty  : Flipping property: storage-server.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-08-23 10:13:02.215  INFO 638408 --- [erListUpdater-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: account-server.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

仔细查看这段日志,我们发现有3个2阶段提交成功(PhaseTwo_Committed),resourceId分别是orderApi、storageApi和accountApi,而在库存服务和账户服务也分别有相关日志的打印,如下:

2020-08-23 10:13:01.123  INFO 645052 --- [nio-8182-exec-3] i.s.sample.service.StorageServiceImpl    : ------->扣减库存prepare开始
2020-08-23 10:13:01.135  INFO 645052 --- [nio-8182-exec-3] i.s.sample.service.StorageServiceImpl    : ------->扣减库存prepare结束
2020-08-23 10:13:01.150  WARN 645052 --- [nio-8182-exec-3] c.a.c.seata.web.SeataHandlerInterceptor  : xid in change during RPC from 192.168.59.132:8091:41466478607220736 to null
2020-08-23 10:13:01.672  INFO 645052 --- [nio-8182-exec-4] i.s.sample.service.StorageServiceImpl    : 扣减库存金额, commit, xid:192.168.59.132:8091:41466478607220736
2020-08-23 10:13:01.358  INFO 643544 --- [nio-8181-exec-1] i.s.sample.service.AccountServiceImpl    : ------->尝试扣减账户开始account
2020-08-23 10:13:01.358  INFO 643544 --- [nio-8181-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-08-23 10:13:01.606  INFO 643544 --- [nio-8181-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-08-23 10:13:01.623  INFO 643544 --- [nio-8181-exec-1] i.s.sample.service.AccountServiceImpl    : ------->尝试扣减账户结束account
2020-08-23 10:13:01.638  WARN 643544 --- [nio-8181-exec-1] c.a.c.seata.web.SeataHandlerInterceptor  : xid in change during RPC from 192.168.59.132:8091:41466478607220736 to null
2020-08-23 10:13:01.686  INFO 643544 --- [nio-8181-exec-2] i.s.sample.service.AccountServiceImpl    : 扣减账户金额, commit, xid:192.168.59.132:8091:41466478607220736

2.模拟rollback事务

修改OrderServiceImpl中create方法,最后一行代码改为如下:

throw new RuntimeException("调用2阶段提交的rollback方法");
//return true

重启服务后,我们再次模拟发送上面的post请求,参数不变,这时查看order-server的日志如下:

前面的日志都一样,我们看一下回滚日志:

2020-08-23 10:54:54.209  INFO 652376 --- [ch_RMROLE_1_1_8] i.s.c.r.p.c.RmBranchRollbackProcessor    : rm handle branch rollback process:xid=192.168.59.132:8091:41477018662486016,branchId=41477022726766592,branchType=TCC,resourceId=accountApi,applicationData={"actionContext":{"sys::rollback":"rollback","sys::commit":"commit","action-start-time":1598324094118,"host-name":"10.192.254.57","sys::prepare":"prepare","actionName":"accountApi"}}
2020-08-23 10:54:54.212  INFO 652376 --- [ch_RMROLE_1_1_8] io.seata.rm.AbstractRMHandler            : Branch Rollbacking: 192.168.59.132:8091:41477018662486016 41477022726766592 accountApi
2020-08-23 10:54:54.247  INFO 652376 --- [ch_RMROLE_1_1_8] io.seata.rm.AbstractResourceManager      : TCC resource rollback result : true, xid: 192.168.59.132:8091:41477018662486016, branchId: 41477022726766592, resourceId: accountApi
2020-08-23 10:54:54.249  INFO 652376 --- [ch_RMROLE_1_1_8] io.seata.rm.AbstractRMHandler            : Branch Rollbacked result: PhaseTwo_Rollbacked
2020-08-23 10:54:54.258  INFO 652376 --- [ch_RMROLE_1_2_8] i.s.c.r.p.c.RmBranchRollbackProcessor    : rm handle branch rollback process:xid=192.168.59.132:8091:41477018662486016,branchId=41477020038217728,branchType=TCC,resourceId=storageApi,applicationData={"actionContext":{"sys::rollback":"rollback","sys::commit":"commit","action-start-time":1598324093476,"host-name":"10.192.254.57","sys::prepare":"decrease","actionName":"storageApi"}}
2020-08-23 10:54:54.258  INFO 652376 --- [ch_RMROLE_1_2_8] io.seata.rm.AbstractRMHandler            : Branch Rollbacking: 192.168.59.132:8091:41477018662486016 41477020038217728 storageApi
2020-08-23 10:54:54.301  INFO 652376 --- [ch_RMROLE_1_2_8] io.seata.rm.AbstractResourceManager      : TCC resource rollback result : true, xid: 192.168.59.132:8091:41477018662486016, branchId: 41477020038217728, resourceId: storageApi
2020-08-23 10:54:54.301  INFO 652376 --- [ch_RMROLE_1_2_8] io.seata.rm.AbstractRMHandler            : Branch Rollbacked result: PhaseTwo_Rollbacked
2020-08-23 10:54:54.306  INFO 652376 --- [ch_RMROLE_1_3_8] i.s.c.r.p.c.RmBranchRollbackProcessor    : rm handle branch rollback process:xid=192.168.59.132:8091:41477018662486016,branchId=41477018775732224,branchType=TCC,resourceId=orderApi,applicationData={"actionContext":{"sys::rollback":"rollback","sys::commit":"commit","action-start-time":1598324093164,"host-name":"10.192.254.57","sys::prepare":"saveOrder","actionName":"orderApi"}}
2020-08-23 10:54:54.306  INFO 652376 --- [ch_RMROLE_1_3_8] io.seata.rm.AbstractRMHandler            : Branch Rollbacking: 192.168.59.132:8091:41477018662486016 41477018775732224 orderApi
2020-08-23 10:54:54.307  INFO 652376 --- [ch_RMROLE_1_3_8] io.seata.sample.service.OrderSaveImpl    : 保存订单金额, rollback, xid:192.168.59.132:8091:41477018662486016
2020-08-23 10:54:54.316  INFO 652376 --- [ch_RMROLE_1_3_8] io.seata.rm.AbstractResourceManager      : TCC resource rollback result : true, xid: 192.168.59.132:8091:41477018662486016, branchId: 41477018775732224, resourceId: orderApi
2020-08-23 10:54:54.316  INFO 652376 --- [ch_RMROLE_1_3_8] io.seata.rm.AbstractRMHandler            : Branch Rollbacked result: PhaseTwo_Rollbacked
2020-08-23 10:54:54.336  INFO 652376 --- [nio-8180-exec-1] i.seata.tm.api.DefaultGlobalTransaction  : [192.168.59.132:8091:41477018662486016] rollback status: Rollbacked
2020-08-23 10:54:54.353 ERROR 652376 --- [nio-8180-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: 调用2阶段提交的rollback方法] with root cause
java.lang.RuntimeException: 调用2阶段提交的rollback方法
  at io.seata.sample.service.OrderServiceImpl.create(OrderServiceImpl.java:65) ~[classes/:na]

可以看出,上面有3个2阶段的事务回滚(PhaseTwo_Rollbacked),resourceId分别是orderApi、storageApi和accountApi,这时我们再看库存服务和账户服务的日志,如下:

2020-08-23 10:54:54.101  INFO 645052 --- [nio-8182-exec-2] i.s.sample.service.StorageServiceImpl    : ------->扣减库存prepare开始
2020-08-23 10:54:54.103  INFO 645052 --- [nio-8182-exec-2] i.s.sample.service.StorageServiceImpl    : ------->扣减库存prepare结束
2020-08-23 10:54:54.105  WARN 645052 --- [nio-8182-exec-2] c.a.c.seata.web.SeataHandlerInterceptor  : xid in change during RPC from 192.168.59.132:8091:41477018662486016 to null
2020-08-23 10:54:54.189  INFO 643544 --- [nio-8181-exec-4] i.s.sample.service.AccountServiceImpl    : ------->尝试扣减账户开始account
2020-08-23 10:54:54.191  INFO 643544 --- [nio-8181-exec-4] i.s.sample.service.AccountServiceImpl    : ------->尝试扣减账户结束account
2020-08-23 10:54:54.192  WARN 643544 --- [nio-8181-exec-4] c.a.c.seata.web.SeataHandlerInterceptor  : xid in change during RPC from 192.168.59.132:8091:41477018662486016 to null
2020-08-23 10:54:54.223  INFO 643544 --- [nio-8181-exec-5] i.s.sample.service.AccountServiceImpl    : 扣减账户金额, rollback, xid:192.168.59.132:8091:41477018662486016

这时我们再查看数据库,3张表都没有变。可见事务确实做了回滚。


总结


分布式事务的TCC模式和AT模式的本质区别是一个是2阶段提交,一个是交易补偿。seata框架对AT模式的支持是非常方便的,但是对TCC模式的支持,最大的就是自动触发commit和prepare方法,真正的实现还是需要开发人员自己做。


大家有更好的实现2阶段事务提交的方法,欢迎指点。

相关文章
|
27天前
|
SQL NoSQL 数据库
SpringCloud基础6——分布式事务,Seata
分布式事务、ACID原则、CAP定理、Seata、Seata的四种分布式方案:XA、AT、TCC、SAGA模式
SpringCloud基础6——分布式事务,Seata
|
27天前
|
负载均衡 Java Nacos
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
微服务介绍、SpringCloud、服务拆分和远程调用、Eureka注册中心、Ribbon负载均衡、Nacos注册中心
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
|
2月前
|
负载均衡 监控 Java
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
|
2月前
|
Java Spring
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
|
2月前
|
关系型数据库 MySQL 数据库
SpringCloud2023中使用Seata解决分布式事务
对于分布式系统而言,需要保证分布式系统中的数据一致性,保证数据在子系统中始终保持一致,避免业务出现问题。分布式系统中对数据的操作要么一起成功,要么一起失败,必须是一个整体性的事务。Seata简化了这个使用过程。
65 2
|
2月前
|
Java Spring 容器
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
|
2月前
|
存储 Java Spring
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
|
2月前
|
SQL Java 数据库连接
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
|
2月前
|
Java 开发工具 Spring
【Azure Spring Cloud】使用azure-spring-boot-starter-storage来上传文件报错: java.net.UnknownHostException: xxxxxxxx.blob.core.windows.net: Name or service not known
【Azure Spring Cloud】使用azure-spring-boot-starter-storage来上传文件报错: java.net.UnknownHostException: xxxxxxxx.blob.core.windows.net: Name or service not known
|
2月前
|
NoSQL Java Redis
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常
【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常