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配置
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