• TCC事务模型


    原理介绍

    TCC事务机制相对于传统事务机制(X/Open XA Two-Phase-Commit),其特征在于它不依赖资源管理器(RM)对XA的支持,而是通过对(由业务系统提供的)业务逻辑的调度来实现分布式事务。主要由三步操作,Try: 尝试执行业务、 Confirm:确认执行业务、 Cancel: 取消执行业务。

    模式特点

    • 该模式对代码的嵌入性高,要求每个业务需要写三种步骤的操作。
    • 该模式对有无本地事务控制都可以支持使用面广。
    • 数据一致性控制几乎完全由开发者控制,对业务开发难度要求高。

    使用场景

    没有带事务的中间件,如:redis

    项目实战

    pom.xml和application.yml文与LCN的一致

    模拟Tcc组合redis

    项目组合:

    • lcn-tm:事务管理者
    • lcn-order:事务发起者
    • lcn-pay:事务参与者
    • cloud-eureka:注册中心

    事务发起者和事务参与者都是TCC

    发起者代码

    package com.dandan.lcnorder.controller;
    
    import com.codingapi.txlcn.tc.annotation.LcnTransaction;
    import com.codingapi.txlcn.tc.annotation.TccTransaction;
    import com.dandan.lcnorder.dao.TblOrderDao;
    import com.dandan.lcnorder.entity.TblOrder;
    import net.sf.json.JSONObject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.BoundValueOperations;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    /**
     * 模拟Tcc组合redis
     */
    @RestController
    public class OrderTccRedisController {
    
        @Autowired
        private TblOrderDao tblOrderDao;
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Autowired
        private RedisTemplate<String,String> redisTemplate;
    
        @PostMapping("/add-order-tcc-redis")
        @Transactional(rollbackFor = Exception.class)
        @TccTransaction
        public String add(@RequestBody TblOrder bean){
    
            JSONObject date = new JSONObject();
            date.put("payName",bean.getOrderName()+"pay");
            restTemplate.postForEntity("http://lcn-pay/add-pay-tcc-redis",date,String.class);
    
            TblOrder tblOrder = new TblOrder();
            tblOrder.setId(1);
            tblOrder.setOrderName("新");
    
            BoundValueOperations<String, String> order = redisTemplate.boundValueOps("order");
            order.set("order-value");
    
            tblOrderDao.updateByPrimaryKey(tblOrder);
            int i = 1/0;
            return "新增订单成功";
        }
    
        public String confirmAdd(TblOrder bean){
            System.out.println("add 确认线程名:"+Thread.currentThread().getName());
            System.out.println("order confirm ");
            return "confirm 订单成功";
        }
    
    ////    private static Map<String,Integer> maps = new HashMap<>();
    //
    //    private ThreadLocal<Integer> ids = new ThreadLocal<>();
    
        public String cancelAdd(TblOrder bean){
            System.out.println("add 取消线程名:"+Thread.currentThread().getName());
            TblOrder tblOrder = new TblOrder();
            tblOrder.setId(1);
            tblOrder.setOrderName("旧");
    
            tblOrderDao.updateByPrimaryKey(tblOrder);
    
            redisTemplate.delete("order");
            System.out.println("order cancel ");
            return "cancel 订单成功";
        }
    }
    

    参与者代码

    package com.dandan.lcnpay.controller;
    
    import com.codingapi.txlcn.tc.annotation.TccTransaction;
    import com.dandan.lcnpay.dao.TblPayDao;
    import com.dandan.lcnpay.entity.TblPay;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 模拟Tcc组合mysql,不建议用,代码复杂度太高,使用LCN更简单
     */
    @RestController
    public class PayTccController {
    
    
        @Autowired
        private TblPayDao tblPayDao;
    
        @PostMapping("/add-pay-tcc")
        @Transactional(rollbackFor = Exception.class)
        @TccTransaction
        public String addPay(@RequestBody TblPay bean){
            tblPayDao.insert(bean);
            Integer id = bean.getId();
            maps.put("a",id);
    //        int i = 1/0;
            return "新增支付成功";
    
        }
        public String confirmAddPay(TblPay bean){
            System.out.println("pay confirm");
            return "新增支付成功";
    
        }
        private static Map<String,Integer> maps = new HashMap<>();
    
        /**
         * 逆sql
         * @param bean
         * @return
         */
        public String cancelAddPay(TblPay bean){
            Integer a = maps.get("a");
            System.out.println("a:"+a);
            System.out.println("pay cancel");
            tblPayDao.deleteByPrimaryKey(a);
            return "取消支付成功";
    
        }
    }
    

    事务发起者是LCN,参与者是TCC

    发起者代码

    package com.dandan.lcnorder.controller;
    
    import com.codingapi.txlcn.tc.annotation.LcnTransaction;
    import com.dandan.lcnorder.dao.TblOrderDao;
    import com.dandan.lcnorder.entity.TblOrder;
    import net.sf.json.JSONObject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.BoundValueOperations;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    /**
     * 模拟Tcc组合redis,LCN组合sql
     * client1使用LCN
     * client2使用TCC
     */
    @RestController
    public class OrderTccRedisController2 {
    
        @Autowired
        private TblOrderDao tblOrderDao;
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Autowired
        private RedisTemplate<String,String> redisTemplate;
    
        @PostMapping("/add-order-tcc-redis2")
        @Transactional(rollbackFor = Exception.class)
        @LcnTransaction
        public String add(@RequestBody TblOrder bean){
    
            JSONObject date = new JSONObject();
            date.put("payName",bean.getOrderName()+"pay");
            restTemplate.postForEntity("http://lcn-pay/add-pay-tcc-redis",date,String.class);
    
            TblOrder tblOrder = new TblOrder();
            tblOrder.setId(1);
            tblOrder.setOrderName("新");
    
            tblOrderDao.updateByPrimaryKey(tblOrder);
            int i = 1/0;
            return "新增订单成功";
        }
    }
    

    参与者代码

    package com.dandan.lcnpay.controller;
    
    import com.dandan.lcnpay.dao.TblPayDao;
    import com.dandan.lcnpay.entity.TblPay;
    import com.dandan.lcnpay.service.RedisService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class PayTccRedisController {
    
    
        @Autowired
        private TblPayDao tblPayDao;
    
        @Autowired
        private RedisService redisService;
    
        @PostMapping("/add-pay-tcc-redis")
        @Transactional(rollbackFor = Exception.class)
        public String addPay(@RequestBody TblPay bean){
            redisService.addPay(null);
    //        int i = 1/0;
            return "新增支付成功";
        }
    }
    

    RedisService代码

    package com.dandan.lcnpay.service;
    
    import com.codingapi.txlcn.tc.annotation.TccTransaction;
    import com.dandan.lcnpay.entity.TblPay;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.BoundValueOperations;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    import org.springframework.web.bind.annotation.RequestBody;
    
    import java.util.HashMap;
    
    @Service
    public class RedisService {
    
        @Autowired
        private RedisTemplate<String,String> redisTemplate;
    
        @TccTransaction
        public String addPay(@RequestBody TblPay bean){
            BoundValueOperations<String, String> pay = redisTemplate.boundValueOps("pay");
            pay.set("pay-value");
    //        int i = 1/0;
            return "新增支付成功";
        }
        public String confirmAddPay(TblPay bean){
            System.out.println("pay confirm");
            return "confirm 支付成功";
    
        }
        private static java.util.Map<String,Integer> maps = new HashMap<>();
    
        /**
         * 逆sql
         * @param bean
         * @return
         */
        public String cancelAddPay(TblPay bean){
            redisTemplate.delete("pay");
            System.out.println("pay cancel");
            return "取消支付成功";
        }
    }
    
  • 相关阅读:
    盒模型新增样式
    css3 文字处理
    popupWindow的用法(1)
    spinner适配器
    layer-list解决listView中相邻item之间线的重叠的问题
    安卓中常用的shape,selector,layer-list
    Pagerstwich tab样式加下拉刷新(三)
    PagerSwitch tab样式加下拉刷新(二)
    PagerSwitch tab样式加上下拉刷新(一)
    listview中textview响应部分文本点击事件
  • 原文地址:https://www.cnblogs.com/zheaven/p/15560278.html
Copyright © 2020-2023  润新知