application.properties 配置文件
spring.application.name=springcloud-portal
server.port=8080
eureka.client.serviceUrl.defaultZone=http://user:1
23456@eureka1:8761/eureka/,http://user:123456@eureka2
:8761/eureka/
2.1.2springcloud-order
pom 文件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.18.RELEASE</version>
</parent><groupId>com.bjsxt</groupId>
<artifactId>springcloud-order</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId
>
</dependency>
<!-- 添加 Feign 坐标 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Mybatis 启动器 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId
><version>1.1.1</version>
</dependency>
<!-- mysql 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
</dependencies>
</project>
application.properties 配置文件
spring.application.name=springcloud-order
server.port=8181
eureka.client.serviceUrl.defaultZone=http://user:1
23456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/
spring.datasource.driverClassName=com.mysql.jdbc.D
river
spring.datasource.url=jdbc:mysql://localhost:3306/
sxt_orders
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.Drui
dDataSource
mybatis.type-aliases-package=com.bjsxt.pojo
2.1.3springcloud-inventory
pom 文件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.18.RELEASE</version>
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-inventory</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement><dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId
>
</dependency>
<!-- 添加 Feign 坐标 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Mybatis 启动器 -->
<dependency><groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId
>
<version>1.1.1</version>
</dependency>
<!-- mysql 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
</dependencies>
</project>
application.properties 配置文件
spring.application.name=springcloud-inventoryserver.port=8282
eureka.client.serviceUrl.defaultZone=http://user:1
23456@eureka1:8761/eureka/,http://user:123456@eureka2
:8761/eureka/
spring.datasource.driverClassName=com.mysql.jdbc.D
river
spring.datasource.url=jdbc:mysql://localhost:3306/
sxt_inventory
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.Drui
dDataSource
mybatis.type-aliases-package=com.bjsxt.pojo
2.2创建服务接口
2.2.1springcloud-order-service
pom 文件
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.18.RELEASE</version>
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-order-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>2.2.2springcloud-inventory-service
pom 文件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.18.RELEASE</version>
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-inventory-service</artifactId
>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
修改 springcloud-inventory 服务的 pom 文件
<dependency>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-inventory-service</artifact
Id>
<version>0.0.1-SNAPSHOT</version>
</dependency>
修改 springcloud-order 服务的 pom 文件
<dependency>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-order-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
修改 springcloud-portal 服务的 pom 文件
<dependency><groupId>com.bjsxt</groupId>
<artifactId>springcloud-order-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.bjsxt</groupId>
<artifactId>springcloud-inventory-service</artifact
Id>
<version>0.0.1-SNAPSHOT</version>
</dependency>
2.3实现业务
2.3.1实现添加订单业务
2.3.1.1 添加 mapper
2.3.1.2 添加业务层
2.3.1.3 添加 controller
2.3.1.4 添加启动类
2.3.1.5 在业务接口项目中添加 pojo
2.3.2实现修改库存商品数量业务
2.3.2.1 添加 mapper
2.3.2.2 添加业务层
2.3.2.3 添加 controller
2.3.2.4 添加启动类
2.3.2.5 在业务接口项目中添加 pojo
2.4实现 portal 中的创建订单业务
2.4.1添加实现服务接口的接口
2.4.2添加 portalService 接口
2.4.3添加 controller
2.4.4添加启动类
2.5测试
目前是不具备分布式事务处理能力的。3 使用 LCN 实现分布式事务处理
3.1下载 LCN 事务协调器
3.2配置事务协调器
3.2.1将事务协调器服务添加到 IDE 中
3.2.2配置事务协调器
#######################################txmanager-s
tart#################################################
#服务端口
server.port=8888
#tx-manager 不得修改
spring.application.name=tx-managerspring.mvc.static-path-pattern=/**
spring.resources.static-locations=classpath:/stati
c/
#######################################txmanager-e
nd#################################################
#zookeeper 地址
#spring.cloud.zookeeper.connect-string=127.0.0.1:2
181
#spring.cloud.zookeeper.discovery.preferIpAddress
= true
#eureka 地址
eureka.client.service-url.defaultZone=http://user:
123456@eureka1:8761/eureka/,http://user:123456@eureka
2:8761/eureka/
#######################################redis-start
#################################################
#redis 配置文件,根据情况选择集群或者单机模式##redis 集群环境配置
##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 单点环境配置
#redis
#redis 主机地址
spring.redis.host=192.168.70.145
#redis 主机端口
spring.redis.port=6379
#redis 链接密码
spring.redis.password=
spring.redis.pool.maxActive=10
spring.redis.pool.maxWait=-1
spring.redis.pool.maxIdle=5
spring.redis.pool.minIdle=0
spring.redis.timeout=0
#####################################redis-end####
######################################################################################LCN-start##
###############################################
#业务模块与 TxManager 之间通讯的最大等待时间(单位:秒)
#通讯时间是指:发起方与响应方之间完成一次的通讯时间。
#该字段代表的是 Tx-Client 模块与 TxManager 模块之间的最
大通讯时间,超过该时间未响应本次请求失败。
tm.transaction.netty.delaytime = 5
#业务模块与 TxManager 之间通讯的心跳时间(单位:秒)
tm.transaction.netty.hearttime = 15
#存储到 redis 下的数据最大保存时间(单位:秒)
#该字段仅代表的事务模块数据的最大保存时间,补偿数据会永
久保存。
tm.redis.savemaxtime=30
#socket server Socket 对外服务端口
#TxManager 的 LCN 协议的端口
tm.socket.port=9999#最大 socket 连接数
#TxManager 最大允许的建立连接数量
tm.socket.maxconnection=100
#事务自动补偿 (true:开启,false:关闭)
# 说明:
# 开启自动补偿以后,必须要配置
tm.compensate.notifyUrl 地址,仅当
tm.compensate.notifyUrl 在请求补偿确认时返回 success 或者
SUCCESS 时,才会执行自动补偿,否则不会自动补偿。
# 关闭自动补偿,当出现数据时也会
tm.compensate.notifyUrl 地址。
# 当 tm.compensate.notifyUrl 无效时,不影响 TxManager
运行,仅会影响自动补偿。
tm.compensate.auto=false
#事务补偿记录回调地址(rest api 地址,post json 格式)
#请求补偿是在开启自动补偿时才会请求的地址。请求分为两种:
1.补偿决策,2.补偿结果通知,可通过通过 action 参数区分
compensate 为补偿请求、notify 为补偿通知。
#*注意当请求补偿决策时,需要补偿服务返回"SUCCESS"字符串以后才可以执行自动补偿。
#请求补偿结果通知则只需要接受通知即可。
#请求补偿的样例数据格式:
#{"groupId":"TtQxTwJP","action":"compensate","json
":"{"address":"133.133.5.100:8081","className":
"com.example.demo.service.impl.DemoServiceImpl","c
urrentTime":1511356150413,"data":"C5IBLWNvbS5leGF
tcGxlLmRlbW8uc2VydmljZS5pbXBsLkRlbW9TZXJ2aWNlSW1wbAwS
BHNhdmUbehBqYXZhLmxhbmcuT2JqZWN0GAAQARwjeg9qYXZhLmxhb
mcuQ2xhc3MYABABJCo/cHVibGljIGludCBjb20uZXhhbXBsZS5kZW
1vLnNlcnZpY2UuaW1wbC5EZW1vU2VydmljZUltcGwuc2F2ZSgp",
"groupId":"TtQxTwJP","methodStr":"public int
com.example.demo.service.impl.DemoServiceImpl.save()
","model":"demo1","state":0,"time":36,"txGro
up":{"groupId":"TtQxTwJP","hasOver":1,"isComp
ensate":0,"list":[{"address":"133.133.5.100:889
9","isCompensate":0,"isGroup":0,"kid":"wnlEJo
Sl","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":1511356150
379,"state":1},"uniqueKey":"be6eea31e382f1f0878d
07cef319e4d7"}"}
#请求补偿的返回数据样例数据格式:
#SUCCESS
#请求补偿结果通知的样例数据格式:
#{"resState":true,"groupId":"TtQxTwJP","action":"n
otify"}
tm.compensate.notifyUrl=http://ip:port/path
#补偿失败,再次尝试间隔(秒),最大尝试次数 3 次,当超过
3 次即为补偿失败,失败的数据依旧还会存在 TxManager 下。
tm.compensate.tryTime=30
#各事务模块自动补偿的时间上限(毫秒)
#指的是模块执行自动超时的最大时间,该最大时间若过段会导
致事务机制异常,该时间必须要模块之间通讯的最大超过时间。
#例如,若模块 A 与模块 B,请求超时的最大时间是 5 秒,则建
议改时间至少大于 5 秒。
tm.compensate.maxWaitTime=5000
#######################################LCN-end####
#############################################logging.level.com.codingapi=debug
3.3访问 TX-Manager 事务协调器的管理页面
访问地址:http://ip:port
3.4创建 TX-Client
3.4.1添加坐标
在所有需要处理分布式事务的微服务中增加下述依赖:为统一资源版本,使用
properties 统一管理版本信息。
<properties>
<lcn.last.version>4.1.0</lcn.last.version>
</properties>
<dependency><groupId>com.codingapi</groupId>
<artifactId>transaction-springcloud</artifactId>
<version>${lcn.last.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.codingapi</groupId>
<artifactId>tx-plugins-db</artifactId>
<version>${lcn.last.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
3.4.2实现接口
使用 LCN 做分布式事务管理时,服务需要知道事务协调器的 URL(客户端与事务协
调器是通过 URL 来建立连接的)。我们需要实现一个接口 TxManagerTxUrlService,这个
接口实现类可以使用独立应用定义,在微服务应用中引入
@Service
public class TxManagerTxUrlServiceImpl implements TxManagerTxUrlService {
@Value("${tm.manager.url}")
private String url;
@Override
public String getTxUrl() {
return url;
}
}
3.4.3创建事务客户端项目
3.4.4修改 pom 文件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/
4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bjsxt</groupId>
<artifactId>tx-trans-manager-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<lcn.last.version>4.1.0</lcn.last.version>
</properties>
<dependencies>
<dependency>
<groupId>com.codingapi</groupId>
<artifactId>transaction-springcloud</artifactId>
<version>${lcn.last.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.codingapi</groupId>
<artifactId>tx-plugins-db</artifactId><version>${lcn.last.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
3.4.5在项目中创建 TxManagerTxUrlService 接口的实现类
@Service
public class TxManagerTxUrlServiceImpl implements
TxManagerTxUrlService {
@Value("${tm.manager.url}")
private String url;
@Override
public String getTxUrl() {
// "http://localhost:8888/tx/manager/";
return url;}
}
3.4.6完成项目的注入
将 tx-trans-manager-service 项目分别注入给 springcloud-inventory、springcloud-order、
springcloud-portal
3.4.7修改客户端服务的配置文件
在客户端服务的全局配置文件中增加下述配置:
# 定义事务协调器所在位置。根据具体环境定义其中的 IP 地址和端口。
tm.manager.url=http://127.0.0.1:8899/tx/manager/
3.5使用 LCN 提供的注解实现分布式事务处理
3.5.1@TxTransaction
3.5.1.1 在整个业务的事务代码中添加注解@TxTransaction。
3.5.1.2 在 事 务 的 起 始 代 码 中 的 @TxTransaction 注 解 中 添 加
isStart=true
3.5.2测试