springcloud整合分布式事务LCN
一、创建eureka注册中心
a、pom文件
1 <properties> 2 <java.version>1.8</java.version> 3 <spring-cloud.version>Greenwich.SR2</spring-cloud.version> 4 </properties> 5 6 <dependencies> 7 <dependency> 8 <groupId>org.springframework.boot</groupId> 9 <artifactId>spring-boot-starter-web</artifactId> 10 </dependency> 11 <dependency> 12 <groupId>org.springframework.cloud</groupId> 13 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> 14 </dependency> 15 16 <dependency> 17 <groupId>org.springframework.boot</groupId> 18 <artifactId>spring-boot-starter-test</artifactId> 19 <scope>test</scope> 20 </dependency> 21 </dependencies> 22 23 <dependencyManagement> 24 <dependencies> 25 <dependency> 26 <groupId>org.springframework.cloud</groupId> 27 <artifactId>spring-cloud-dependencies</artifactId> 28 <version>${spring-cloud.version}</version> 29 <type>pom</type> 30 <scope>import</scope> 31 </dependency> 32 </dependencies> 33 </dependencyManagement>
b、properties文件
server.port=8761 #禁止将自己注册到注册中心 eureka.client.register-with-eureka=false eureka.instance.hostname=localhost eureka.client.fetch-registry=false eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/ eureka.server.enable-self-preservation=false spring.cloud.config.discovery.enabled=true
c、在启动类上加上@EnableEurekaServer注解
@SpringBootApplication @EnableEurekaServer public class SpringcloudEurekaApplication { public static void main(String[] args) { SpringApplication.run(SpringcloudEurekaApplication.class, args); } }
d、启动该服务
二、创建微服务A
a、pom文件
1 <properties> 2 <java.version>1.8</java.version> 3 <spring-cloud.version>Greenwich.SR2</spring-cloud.version> 4 </properties> 5 6 <dependencies> 7 <dependency> 8 <groupId>org.springframework.boot</groupId> 9 <artifactId>spring-boot-starter-data-jpa</artifactId> 10 </dependency> 11 <dependency> 12 <groupId>org.springframework.boot</groupId> 13 <artifactId>spring-boot-starter-web</artifactId> 14 </dependency> 15 <dependency> 16 <groupId>org.springframework.cloud</groupId> 17 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 18 </dependency> 19 20 <dependency> 21 <groupId>mysql</groupId> 22 <artifactId>mysql-connector-java</artifactId> 23 <scope>runtime</scope> 24 </dependency> 25 <dependency> 26 <groupId>org.springframework.boot</groupId> 27 <artifactId>spring-boot-starter-test</artifactId> 28 <scope>test</scope> 29 </dependency> 30 <dependency> 31 <groupId>com.alibaba</groupId> 32 <artifactId>druid</artifactId> 33 <version>1.0.9</version> 34 </dependency> 35 <dependency> 36 <groupId>org.springframework.cloud</groupId> 37 <artifactId>spring-cloud-starter-openfeign</artifactId> 38 </dependency> 39 </dependencies>
b、properties文件
spring.application.name=springcloud-aservice server.port=8080 eureka.client.service-url.defaultZone=http://localhost:8761/eureka/ #spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.username=root spring.datasource.password=123456 spring.datasource.url=jdbc:mysql://localhost:3306/yzh?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true #################jpa配置#################### spring.jpa.database=mysql spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
c、在启动类上添加@EnableEurekaClient注解
d、创建entity
1 @Entity 2 public class Orders implements Serializable{ 3 4 private static final long serialVersionUID = 3295617400035010415L; 5 6 @Id 7 @GeneratedValue(strategy = GenerationType.IDENTITY) 8 private Integer orderId; 9 10 private Integer itemId; 11 12 private Integer price; 13 14 public Integer getOrderId() { 15 return orderId; 16 } 17 18 public void setOrderId(Integer orderId) { 19 this.orderId = orderId; 20 } 21 22 public Integer getItemId() { 23 return itemId; 24 } 25 26 public void setItemId(Integer itemId) { 27 this.itemId = itemId; 28 } 29 30 public Integer getPrice() { 31 return price; 32 } 33 34 public void setPrice(Integer price) { 35 this.price = price; 36 } 37 }
e、创建dao
public interface OrderDao extends JpaRepository<Orders,Integer> { }
f、创建service
1 @Service 2 public class OrderService { 3 4 @Autowired 5 private OrderDao orderDao; 6 @Autowired 7 private InventoryService inventoryService; 8 9 @Transactional 10 public Orders addOrder(){ 11 Orders orders = new Orders(); 12 orders.setItemId(100); 13 orders.setPrice(2000); 14 15 Orders save = orderDao.save(orders); 16 17 inventoryService.updateInventory(100,9); 18 19 return save; 20 } 21 }
g、创建feign调用
1 @FeignClient(value = "springcloud-bservice",fallback = InventoryServiceFallback.class) 2 public interface InventoryService { 3 4 @GetMapping(value = "updateInventory") 5 Object updateInventory(@RequestParam(value = "itemId") Integer itemId,@RequestParam(value = "itemNum") Integer itemNum); 6 7 } 8 9 //回调类 10 public class InventoryServiceFallback implements InventoryService{ 11 @Override 12 public Object updateInventory(Integer itemId, Integer itemNum) { 13 return 0; 14 } 15 }
h、在启动类上添加@EnableFeignClients注解
i、创建web
@RestController public class OrdersController { @Autowired private OrderService orderService; @RequestMapping("/addOrders") public Object addOrders(){ return orderService.addOrder(); } }
三、创建微服务B
a、pom文件
1 <properties> 2 <java.version>1.8</java.version> 3 <spring-cloud.version>Greenwich.SR2</spring-cloud.version> 4 </properties> 5 6 <dependencies> 7 <dependency> 8 <groupId>org.springframework.boot</groupId> 9 <artifactId>spring-boot-starter-data-jpa</artifactId> 10 </dependency> 11 <dependency> 12 <groupId>org.springframework.boot</groupId> 13 <artifactId>spring-boot-starter-web</artifactId> 14 </dependency> 15 <dependency> 16 <groupId>org.springframework.cloud</groupId> 17 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> 18 </dependency> 19 20 <dependency> 21 <groupId>mysql</groupId> 22 <artifactId>mysql-connector-java</artifactId> 23 <scope>runtime</scope> 24 </dependency> 25 <dependency> 26 <groupId>org.springframework.boot</groupId> 27 <artifactId>spring-boot-starter-test</artifactId> 28 <scope>test</scope> 29 </dependency> 30 </dependencies>
b、properties文件
spring.application.name=springcloud-bservice server.port=8081 eureka.client.service-url.defaultZone=http://localhost:8761/eureka/ #spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.username=root spring.datasource.password=123456 spring.datasource.url=jdbc:mysql://localhost:3306/yzh?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true #################jpa配置#################### spring.jpa.database=mysql spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
c、在启动类上添加@EnableEurekaClient注解
d、创建entity
1 @Entity 2 @Table(name = "tb_inventory") 3 public class TbInventory implements Serializable{ 4 private static final long serialVersionUID = 4171468306443543867L; 5 6 @Id 7 @GeneratedValue(strategy = GenerationType.IDENTITY) 8 private Integer inventoryId; 9 10 private Integer itemId; 11 12 private Integer itemnum; 13 14 public Integer getInventoryId() { 15 return inventoryId; 16 } 17 18 public void setInventoryId(Integer inventoryId) { 19 this.inventoryId = inventoryId; 20 } 21 22 public Integer getItemId() { 23 return itemId; 24 } 25 26 public void setItemId(Integer itemId) { 27 this.itemId = itemId; 28 } 29 30 public Integer getItemnum() { 31 return itemnum; 32 } 33 34 public void setItemnum(Integer itemnum) { 35 this.itemnum = itemnum; 36 } 37 }
e、创建dao
public interface TbInventoryDao extends JpaRepository<TbInventory,Integer> { }
f、创建service
1 @Service 2 public class TbInventoryService { 3 4 @Autowired 5 private TbInventoryDao tbInventoryDao; 6 7 8 @Transactional 9 public TbInventory updateInventory(Integer itemId,Integer itemNum){ 10 TbInventory tbInventory = new TbInventory(); 11 tbInventory.setItemId(itemId); 12 tbInventory.setItemnum(itemNum); 13 TbInventory save = tbInventoryDao.save(tbInventory); 14 System.err.println(1/0); 15 return save; 16 17 } 18 }
g、创建web
@RestController public class TbInventoryController { @Autowired private TbInventoryService tbInventoryService; @GetMapping("updateInventory") public Object updateInventory(@RequestParam Integer itemId, @RequestParam Integer itemNum){ return tbInventoryService.updateInventory(itemId,itemNum); } }
四、引入LCN
a、下载地址:https://github.com/codingapi/tx-lcn/releases
(此处下载的是版本5.0.2.RELEASE)
b、将项目txlcn-tm导入idea,并修改properties文件
spring.application.name=tx-manager server.port=7970 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tx-manager?characterEncoding=UTF-8 spring.datasource.username=root spring.datasource.password=root mybatis.configuration.map-underscore-to-camel-case=true mybatis.configuration.use-generated-keys=true #tx-lcn.logger.enabled=true # TxManager Host Ip #tx-lcn.manager.host=127.0.0.1 # TxClient连接请求端口 #tx-lcn.manager.port=8070 # 心跳检测时间(ms) #tx-lcn.manager.heart-time=15000 # 分布式事务执行总时间 #tx-lcn.manager.dtx-time=30000 #参数延迟删除时间单位ms #tx-lcn.message.netty.attr-delay-time=10000 #tx-lcn.manager.concurrent-level=128 # 开启日志 #tx-lcn.logger.enabled=true #logging.level.com.codingapi=debug #redis 主机 #spring.redis.host=127.0.0.1 #redis 端口 #spring.redis.port=6379 #redis 密码 #spring.redis.password=
-
#
给出信息都是默认值
关于详细配置说明见TM配置 -
application.properties 加载顺序如下:
0、命令行启动参数指定
1、file:./config/(当前jar目录下的config目录)
2、file:./(当前jar目录)
3、classpath:/config/(classpath下的config目录)
4、classpath:/(classpath根目录)
发布的二进制可执行Jar包含一个默认配置文件(也就是4),可按需要覆盖默认配置
c、创建MySQL数据库, 名称为: tx-manager、然后创建数据表
CREATE TABLE `t_tx_exception` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `group_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `unit_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `mod_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `transaction_state` tinyint(4) NULL DEFAULT NULL, `registrar` tinyint(4) NULL DEFAULT NULL, `remark` varchar(4096) NULL DEFAULT NULL, `ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 未解决 1已解决', `create_time` datetime(0) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
d、将项目改造成springcloud项目,并注册到eureka中
1 <properties> 2 <java.version>1.8</java.version> 3 <spring-cloud.version>Finchley.RELEASE</spring-cloud.version> 4 <spring-boot.version>2.1.7.RELEASE</spring-boot.version> 5 </properties> 6 7 <dependency> 8 <groupId>org.springframework.boot</groupId> 9 <artifactId>spring-boot-starter-data-redis</artifactId> 10 <version>${spring-boot.version}</version> 11 </dependency> 12 13 <dependency> 14 <groupId>org.springframework.boot</groupId> 15 <artifactId>spring-boot-starter-mail</artifactId> 16 <version>${spring-boot.version}</version> 17 </dependency> 18 <dependency> 19 <groupId>org.springframework.boot</groupId> 20 <artifactId>spring-boot-starter-data-jpa</artifactId> 21 <version>${spring-boot.version}</version> 22 </dependency> 23 <dependency> 24 <groupId>org.springframework.cloud</groupId> 25 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> 26 </dependency>
注意:为了防止版本冲突需要知道springboot的版本为2.1.x,并且设置springcloud的版本为Finchley.RELEASE,还要在properties文件中新增配置:spring.cloud.compatibility-verifier.enabled=false
c、将项目注册到eureka中
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
d、在启动类上添加@EnableEurekaClient注解
五、开始整合
a、在服务A、B的pom文件中引入坐标
1 <dependency> 2 <groupId>com.codingapi.txlcn</groupId> 3 <artifactId>txlcn-tc</artifactId> 4 <version>5.0.2.RELEASE</version> 5 <exclusions> 6 <exclusion> 7 <groupId>org.springframework.boot</groupId> 8 <artifactId>*</artifactId> 9 </exclusion> 10 </exclusions> 11 </dependency> 12 13 <dependency> 14 <groupId>com.codingapi.txlcn</groupId> 15 <artifactId>txlcn-txmsg-netty</artifactId> 16 <version>5.0.2.RELEASE</version> 17 <exclusions> 18 <exclusion> 19 <groupId>org.springframework.boot</groupId> 20 <artifactId>*</artifactId> 21 </exclusion> 22 </exclusions> 23 </dependency>
注意:为了防止springboot的jar包冲突,需要将里面关于springboot的所有jar包排除掉。
b、在服务A、B的启动类上添加注解@EnableDistributedTransaction启动分布式事务
c、在服务A中的需要分布式事务方法上面添加@LcnTransaction,服务B中添加@TxcTransaction注解。
六、启动、测试
a、依次启动eureka注册中心,txlcn-tm,服务A、B
b、调用服务