1  LCN介绍

利用事务管理器,统一协调各个本地事务,实现事务的一致性。

 

特性:

1、一致性,通过TxManager协调控制与事务补偿机制确保数据一致性

2、易用性,仅需要在业务方法上添加@TxTransaction注解即可

3、高可用,项目模块不仅可高可用部署,事务协调器也可集群化部署

4、扩展性,支持各种RPC框架扩展,支持通讯协议与事务模式扩展

 

官方文档:https://www.txlcn.org/zh-cn/docs/preface.html

源码参考:https://gitee.com/wangliang1991/tx-lcn/tree/4.1.0/

 

2  tx-manager资源管理器改造

下载资源管理器代码 tx-manager,进行改造,可自行调整注册中心和redis集成等。

修改配置application.properties

调整端口、注册中心配置,redis配置

tx-manager.zip

3  分布式事务集成使用

3.1 微服务service-1改造

3.1.1  添加pom依赖配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--分布式事务配置-->
    <dependency>
        <groupId>com.codingapi</groupId>
        <artifactId>transaction-springcloud</artifactId>
        <version>4.1.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.codingapi</groupId>
        <artifactId>tx-plugins-db</artifactId>
        <version>4.1.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!--分布式事务配置-->

  

3.1.2  添加tx-manger地址配置

新增tx.properties

url=http://127.0.0.1:9000/tx/manager/

3.1.3 添加测试接口

1
2
3
4
5
6
7
8
9
10
11
12
@RestController
    @RequestMapping("/test")
    public class TestController {
        private static Logger LOGGER = LoggerFactory.getLogger(TestController.class);
        @Autowired
        private IDemoService demoService;
        @PostMapping(value = "/save", produces = "application/json;charset=utf-8")
        @ResponseBody
        public int save(){
            return demoService.save();
        }
    }

  

1
2
3
4
public interface IDemoService {
    List<Test> list();
    int save();
}

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Service
    public class DemoServiceImpl implements IDemoService /*,ITxTransaction*/ {
        @Autowired
        private ITestDao testDao;
        private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
        @Override
        public List<Test> list() {
            return testDao.findAll();
        }
        /**
     *  @TxTransaction(isStart = false) //true:事务发起方 false: 事务参与方 ,默认为参与方
     *   参与方添加注解@TxTransaction或者实现接口ITxTransaction效果一样。
     * @return
     */
    @Override
    @TxTransaction
    @Transactional
    public int save() {
            int rs1 = testDao.save("test-service-2");
            return rs1;
        }
    }

  

1
2
3
4
5
6
7
@Mapper
    public interface ITestDao {
        @Select("SELECT * FROM t_test")
        List<Test> findAll();
        @Insert("INSERT INTO t_test(name) VALUES(#{name})")
        int save(@Param("name") String name);
    }

  

3.2  微服务service-2改造

 

3.2.1  添加pom依赖配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--分布式事务配置-->
    <dependency>
        <groupId>com.codingapi</groupId>
        <artifactId>transaction-springcloud</artifactId>
        <version>4.1.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.codingapi</groupId>
        <artifactId>tx-plugins-db</artifactId>
        <version>4.1.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!--分布式事务配置-->

  

3.2.2  添加tx-manger地址配置

新增tx.properties

url=http://127.0.0.1:9000/tx/manager/

 

3.2.3 添加测试接口

1
2
3
4
5
6
7
8
9
10
11
12
@RestController
    @RequestMapping("/test")
    public class TestController {
        private static Logger LOGGER = LoggerFactory.getLogger(TestController.class);
        @Autowired
        private IDemoService demoService;
        @PostMapping(value = "/save", produces = "application/json;charset=utf-8")
        @ResponseBody
        public int save(){
            return demoService.save();
        }
    }

  

1
2
3
4
public interface IDemoService {
    List<Test> list();
    int save();
    }

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Service
    public class DemoServiceImpl implements IDemoService {
        @Autowired
        private ServiceFeignClient serviceFeignClient;
        @Autowired
        private ITestDao testDao;
        private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
        @Override
        public List<Test> list() {
            return testDao.findAll();
        }
 
        @Override
        @TxTransaction(isStart = true//true:事务发起方 false:事务参与方
        @Transactional
        public int save() {
            int rs1 = testDao.save("test-service-2");
            int rs2 = serviceFeignClient.save();
            int v = 100/0;
            return rs1+rs2;
        }
    }

  

1
2
3
4
5
6
7
@Mapper
    public interface ITestDao {
        @Select("SELECT * FROM t_test")
        List<Test> findAll();
        @Insert("INSERT INTO t_test(name) VALUES(#{name})")
        int save(@Param("name") String name);
    }

  

3.2.4 添加feign配置

1
2
3
4
5
6
@FeignClient(name = "service-1")
  public interface ServiceFeignClient {
      @PostMapping(value = "/test/save")
      @ResponseBody
      int save();
  }

 

配置文件:
#######################################txmanager-start#################################################
#\u670D\u52A1\u7AEF\u53E3
server.port=9000
#tx-manager\u4E0D\u5F97\u4FEE\u6539
spring.application.name=tx-manager

# \u5F00\u542FAPI\u6CE8\u518C\u529F\u80FD \u672C\u5730dev\u9700\u8981\u5173\u95ED \u5426\u5219\u4F1A\u62A5Value is too long
tsf.swagger.enabled=false
logging.file=/supplier-logs/${spring.application.name}.log

spring.mvc.static-path-pattern=/**
spring.resources.static-locations=classpath:/static/
#######################################txmanager-end#################################################

#zookeeper\u5730\u5740
#spring.cloud.zookeeper.connect-string=127.0.0.1:2181
#spring.cloud.zookeeper.discovery.preferIpAddress = true

#eureka \u5730\u5740
eureka.client.service-url.defaultZone=http://127.0.0.1:65/eureka/
eureka.instance.prefer-ip-address=true

#######################################redis-start#################################################
#redis \u914D\u7F6E\u6587\u4EF6\uFF0C\u6839\u636E\u60C5\u51B5\u9009\u62E9\u96C6\u7FA4\u6216\u8005\u5355\u673A\u6A21\u5F0F

##redis \u96C6\u7FA4\u73AF\u5883\u914D\u7F6E
##redis cluster
#spring.redis.cluster.nodes=127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003
#spring.redis.cluster.commandTimeout=5000

#redis
spring.redis.hostName=192.168.1.1
spring.redis.port=7000
# REDIS (RedisProperties)
# Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09
spring.redis.database=0
# Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09
spring.redis.password=1234567
# \u8FDE\u63A5\u6C60\u6700\u5927\u8FDE\u63A5\u6570\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09
# \u8FDE\u63A5\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09
spring.redis.timeout=5000
spring.redis.pool.max-active= 3000
# \u8FDE\u63A5\u6C60\u6700\u5927\u963B\u585E\u7B49\u5F85\u65F6\u95F4\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09
spring.redis.pool.max-wait=5000
# \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5
spring.redis.pool.max-idle=1000
# \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5
spring.redis.pool.min-idle=200
spring.session.store-type=redis
#redis\u914D\u7F6E*********************
#####################################redis-end###################################################




#######################################LCN-start#################################################
#\u4E1A\u52A1\u6A21\u5757\u4E0ETxManager\u4E4B\u95F4\u901A\u8BAF\u7684\u6700\u5927\u7B49\u5F85\u65F6\u95F4\uFF08\u5355\u4F4D\uFF1A\u79D2\uFF09
#\u901A\u8BAF\u65F6\u95F4\u662F\u6307\uFF1A\u53D1\u8D77\u65B9\u4E0E\u54CD\u5E94\u65B9\u4E4B\u95F4\u5B8C\u6210\u4E00\u6B21\u7684\u901A\u8BAF\u65F6\u95F4\u3002
#\u8BE5\u5B57\u6BB5\u4EE3\u8868\u7684\u662FTx-Client\u6A21\u5757\u4E0ETxManager\u6A21\u5757\u4E4B\u95F4\u7684\u6700\u5927\u901A\u8BAF\u65F6\u95F4\uFF0C\u8D85\u8FC7\u8BE5\u65F6\u95F4\u672A\u54CD\u5E94\u672C\u6B21\u8BF7\u6C42\u5931\u8D25\u3002
tm.transaction.netty.delaytime = 5

#\u4E1A\u52A1\u6A21\u5757\u4E0ETxManager\u4E4B\u95F4\u901A\u8BAF\u7684\u5FC3\u8DF3\u65F6\u95F4\uFF08\u5355\u4F4D\uFF1A\u79D2\uFF09
tm.transaction.netty.hearttime = 15

#\u5B58\u50A8\u5230redis\u4E0B\u7684\u6570\u636E\u6700\u5927\u4FDD\u5B58\u65F6\u95F4\uFF08\u5355\u4F4D\uFF1A\u79D2\uFF09
#\u8BE5\u5B57\u6BB5\u4EC5\u4EE3\u8868\u7684\u4E8B\u52A1\u6A21\u5757\u6570\u636E\u7684\u6700\u5927\u4FDD\u5B58\u65F6\u95F4\uFF0C\u8865\u507F\u6570\u636E\u4F1A\u6C38\u4E45\u4FDD\u5B58\u3002
tm.redis.savemaxtime=30

#socket server Socket\u5BF9\u5916\u670D\u52A1\u7AEF\u53E3
#TxManager\u7684LCN\u534F\u8BAE\u7684\u7AEF\u53E3
tm.socket.port=9999

#\u6700\u5927socket\u8FDE\u63A5\u6570
#TxManager\u6700\u5927\u5141\u8BB8\u7684\u5EFA\u7ACB\u8FDE\u63A5\u6570\u91CF
tm.socket.maxconnection=100

#\u4E8B\u52A1\u81EA\u52A8\u8865\u507F (true:\u5F00\u542F\uFF0Cfalse:\u5173\u95ED)
# \u8BF4\u660E\uFF1A
# \u5F00\u542F\u81EA\u52A8\u8865\u507F\u4EE5\u540E\uFF0C\u5FC5\u987B\u8981\u914D\u7F6E tm.compensate.notifyUrl \u5730\u5740\uFF0C\u4EC5\u5F53tm.compensate.notifyUrl \u5728\u8BF7\u6C42\u8865\u507F\u786E\u8BA4\u65F6\u8FD4\u56DEsuccess\u6216\u8005SUCCESS\u65F6\uFF0C\u624D\u4F1A\u6267\u884C\u81EA\u52A8\u8865\u507F\uFF0C\u5426\u5219\u4E0D\u4F1A\u81EA\u52A8\u8865\u507F\u3002
# \u5173\u95ED\u81EA\u52A8\u8865\u507F\uFF0C\u5F53\u51FA\u73B0\u6570\u636E\u65F6\u4E5F\u4F1A tm.compensate.notifyUrl \u5730\u5740\u3002
# \u5F53tm.compensate.notifyUrl \u65E0\u6548\u65F6\uFF0C\u4E0D\u5F71\u54CDTxManager\u8FD0\u884C\uFF0C\u4EC5\u4F1A\u5F71\u54CD\u81EA\u52A8\u8865\u507F\u3002
tm.compensate.auto=false

#\u4E8B\u52A1\u8865\u507F\u8BB0\u5F55\u56DE\u8C03\u5730\u5740(rest api \u5730\u5740\uFF0Cpost json\u683C\u5F0F)
#\u8BF7\u6C42\u8865\u507F\u662F\u5728\u5F00\u542F\u81EA\u52A8\u8865\u507F\u65F6\u624D\u4F1A\u8BF7\u6C42\u7684\u5730\u5740\u3002\u8BF7\u6C42\u5206\u4E3A\u4E24\u79CD\uFF1A1.\u8865\u507F\u51B3\u7B56\uFF0C2.\u8865\u507F\u7ED3\u679C\u901A\u77E5\uFF0C\u53EF\u901A\u8FC7\u901A\u8FC7action\u53C2\u6570\u533A\u5206compensate\u4E3A\u8865\u507F\u8BF7\u6C42\u3001notify\u4E3A\u8865\u507F\u901A\u77E5\u3002
#*\u6CE8\u610F\u5F53\u8BF7\u6C42\u8865\u507F\u51B3\u7B56\u65F6\uFF0C\u9700\u8981\u8865\u507F\u670D\u52A1\u8FD4\u56DE"SUCCESS"\u5B57\u7B26\u4E32\u4EE5\u540E\u624D\u53EF\u4EE5\u6267\u884C\u81EA\u52A8\u8865\u507F\u3002
#\u8BF7\u6C42\u8865\u507F\u7ED3\u679C\u901A\u77E5\u5219\u53EA\u9700\u8981\u63A5\u53D7\u901A\u77E5\u5373\u53EF\u3002
#\u8BF7\u6C42\u8865\u507F\u7684\u6837\u4F8B\u6570\u636E\u683C\u5F0F:
#{"groupId":"TtQxTwJP","action":"compensate","json":"{\"address\":\"133.133.5.100:8081\",\"className\":\"com.example.demo.service.impl.DemoServiceImpl\",\"currentTime\":1511356150413,\"data\":\"C5IBLWNvbS5leGFtcGxlLmRlbW8uc2VydmljZS5pbXBsLkRlbW9TZXJ2aWNlSW1wbAwSBHNhdmUbehBqYXZhLmxhbmcuT2JqZWN0GAAQARwjeg9qYXZhLmxhbmcuQ2xhc3MYABABJCo/cHVibGljIGludCBjb20uZXhhbXBsZS5kZW1vLnNlcnZpY2UuaW1wbC5EZW1vU2VydmljZUltcGwuc2F2ZSgp\",\"groupId\":\"TtQxTwJP\",\"methodStr\":\"public int com.example.demo.service.impl.DemoServiceImpl.save()\",\"model\":\"demo1\",\"state\":0,\"time\":36,\"txGroup\":{\"groupId\":\"TtQxTwJP\",\"hasOver\":1,\"isCompensate\":0,\"list\":[{\"address\":\"133.133.5.100:8899\",\"isCompensate\":0,\"isGroup\":0,\"kid\":\"wnlEJoSl\",\"methodStr\":\"public int com.example.demo.service.impl.DemoServiceImpl.save()\",\"model\":\"demo2\",\"modelIpAddress\":\"133.133.5.100:8082\",\"channelAddress\":\"/133.133.5.100:64153\",\"notify\":1,\"uniqueKey\":\"bc13881a5d2ab2ace89ae5d34d608447\"}],\"nowTime\":0,\"startTime\":1511356150379,\"state\":1},\"uniqueKey\":\"be6eea31e382f1f0878d07cef319e4d7\"}"}
#\u8BF7\u6C42\u8865\u507F\u7684\u8FD4\u56DE\u6570\u636E\u6837\u4F8B\u6570\u636E\u683C\u5F0F:
#SUCCESS
#\u8BF7\u6C42\u8865\u507F\u7ED3\u679C\u901A\u77E5\u7684\u6837\u4F8B\u6570\u636E\u683C\u5F0F:
#{"resState":true,"groupId":"TtQxTwJP","action":"notify"}
tm.compensate.notifyUrl=http://ip:port/path

#\u8865\u507F\u5931\u8D25\uFF0C\u518D\u6B21\u5C1D\u8BD5\u95F4\u9694\uFF08\u79D2\uFF09\uFF0C\u6700\u5927\u5C1D\u8BD5\u6B21\u65703\u6B21\uFF0C\u5F53\u8D85\u8FC73\u6B21\u5373\u4E3A\u8865\u507F\u5931\u8D25,\u5931\u8D25\u7684\u6570\u636E\u4F9D\u65E7\u8FD8\u4F1A\u5B58\u5728TxManager\u4E0B\u3002
tm.compensate.tryTime=30

#\u5404\u4E8B\u52A1\u6A21\u5757\u81EA\u52A8\u8865\u507F\u7684\u65F6\u95F4\u4E0A\u9650(\u6BEB\u79D2)
#\u6307\u7684\u662F\u6A21\u5757\u6267\u884C\u81EA\u52A8\u8D85\u65F6\u7684\u6700\u5927\u65F6\u95F4\uFF0C\u8BE5\u6700\u5927\u65F6\u95F4\u82E5\u8FC7\u6BB5\u4F1A\u5BFC\u81F4\u4E8B\u52A1\u673A\u5236\u5F02\u5E38\uFF0C\u8BE5\u65F6\u95F4\u5FC5\u987B\u8981\u6A21\u5757\u4E4B\u95F4\u901A\u8BAF\u7684\u6700\u5927\u8D85\u8FC7\u65F6\u95F4\u3002
#\u4F8B\u5982\uFF0C\u82E5\u6A21\u5757A\u4E0E\u6A21\u5757B\uFF0C\u8BF7\u6C42\u8D85\u65F6\u7684\u6700\u5927\u65F6\u95F4\u662F5\u79D2\uFF0C\u5219\u5EFA\u8BAE\u6539\u65F6\u95F4\u81F3\u5C11\u5927\u4E8E5\u79D2\u3002
tm.compensate.maxWaitTime=5000
#######################################LCN-end#################################################


logging.level.com.codingapi=debug



mpmt.sm4.enable=false
mpmt.mongodb.enabled=false

  

 

转自https://www.cnblogs.com/brant/p/12547183.html