- 使用nacos做注冊中心和配置中心
- 使用openfeign做http調(diào)用
- mysql 業(yè)務(wù)庫:seata_order俏险、seata_stock
1. 創(chuàng)建業(yè)務(wù)庫
1.1. seata_order
CREATE TABLE `order_tbl` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int DEFAULT '0',
`money` int DEFAULT '0',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `undo_log` (
`id` bigint NOT NULL AUTO_INCREMENT,
`branch_id` bigint NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.2. seata_stock
CREATE TABLE `stock_tbl` (
`id` int NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int DEFAULT '0',
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `commodity_code` (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `seata_stock`.`stock_tbl` (`id`, `commodity_code`, `count`, `update_time`) VALUES ('1', 'product-1', '-17', '2023-01-30 09:07:36');
INSERT INTO `seata_stock`.`stock_tbl` (`id`, `commodity_code`, `count`, `update_time`) VALUES ('2', 'product-2', '-7', '2023-01-30 01:39:01');
CREATE TABLE `undo_log` (
`id` bigint NOT NULL AUTO_INCREMENT,
`branch_id` bigint NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2. demo項(xiàng)目
- parent項(xiàng)目 springboot-openfeign-seataat
- 三個(gè)子項(xiàng)目
- rm-stock,使用seata_stock庫涤浇《漳扣除商品津畸,更新stock_tbl表
- rm-order蠢护,使用seata_order庫。新建訂單箍土,向order_tbl表插入記錄
- tm-portal逢享,調(diào)用rm-order下單,調(diào)用rm-stock扣除商品
2.1. parent項(xiàng)目
刪除src目錄吴藻,修改pom.xml
<groupId>com.cccc</groupId>
<artifactId>springboot-openfeign-seataat</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>rm-stock</module>
<module>rm-order</module>
<module>tm-portal</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.4</spring-cloud.version>
<spring-boot.version>2.6.11</spring-boot.version>
<spring.cloud.alibaba.version>2021.0.4.0</spring.cloud.alibaba.version>
<seata.version>1.4.2</seata.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Maven properties -->
<mysql-connector.version>5.1.44</mysql-connector.version>
<guava.version>27.0.1-jre</guava.version>
<jackson.version>2.13.4.1</jackson.version>
<druid.version>1.1.12</druid.version>
<jakarta-annotation-api.version>1.3.5</jakarta-annotation-api.version>
<javax.annotation-api.version>1.3.1</javax.annotation-api.version>
<lombok.version>1.18.8</lombok.version>
<maven-source-plugin.version>3.0.1</maven-source-plugin.version>
<maven-surefire-plugin.version>2.22.1</maven-surefire-plugin.version>
<mybatis-plus-boot-starter.version>3.3.0</mybatis-plus-boot-starter.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--mybatis-spring-boot-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--druid-spring-boot連接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.11</version>
</dependency>
</dependencies>
</dependencyManagement>
2.2. rm-stock
- pom.xml
<parent>
<artifactId>springboot-openfeign-seataat</artifactId>
<groupId>com.cccc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rm-stock</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>${spring.cloud.alibaba.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
<!-- mybatis -->
<!--mybatis-generator-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
<!--mybatis-generator-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>11.8</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
- applicaion.properties
spring.application.name=stock-service
server.port=9091
# Nacos 注冊中心地址
spring.cloud.nacos.discovery.server-addr = xx.xx.xx.xx:8848
spring.cloud.nacos.discovery.namespace = nnnnn
spring.cloud.nacos.discovery.register-enabled = true
spring.cloud.nacos.discovery.username = uuuuu
spring.cloud.nacos.discovery.password=ppppp
spring.cloud.nacos.discovery.group=SEATA_GROUP
# 數(shù)據(jù)源配置
spring.datasource.url=jdbc:mysql://xx.xx.xx.xx:3306/seata_stock?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=ppppp
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#事務(wù)分組配置(在v1.5之后默認(rèn)值為default_tx_group)
seata.tx-service-group=seata-storage-service
#指定事務(wù)分組至集群映射關(guān)系(等號右側(cè)的集群名需要與Seata-server注冊到Nacos的cluster保持一致)
seata.service.vgroup-mapping.seata-storage-service=default
#使用nacos作為注冊中心
seata.registry.type=nacos
#nacos注冊中心IP:端口
seata.registry.nacos.server-addr=xx.xx.xx.xx:8848
seata.registry.nacos.username = uuuuu
seata.registry.nacos.password = ppppp
seata.registry.nacos.namespace = nnnnn
seata.registry.nacos.cluster = default
#Seata服務(wù)名(應(yīng)與seata-server實(shí)際注冊的服務(wù)名一致)
seata.registry.nacos.application=seata-server
#Seata分組名(應(yīng)與seata-server實(shí)際注冊的分組名一致)
seata.registry.nacos.group=SEATA_GROUP
#log
#logging.level.io.seata=debug
#logging.level.org.springframework = debug
3.啟動類
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class StockServiceApplication {
public static void main(String[] args) {
SpringApplication.run(StockServiceApplication.class, args);
}
}
- 實(shí)體類
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
@Data
@Accessors(chain = true)
@TableName("stock_tbl")
public class Stock {
private Long id;
private String commodityCode;
private Long count;
private Date updateTime;
}
- dao
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cccc.entity.Stock;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface StockDAO extends BaseMapper<Stock> {
}
- service
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cccc.entity.Stock;
import com.cccc.repository.StockDAO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;
@Service
public class StockService {
@Resource
private StockDAO stockDAO;
/**
* 減庫存
*
* @param commodityCode
* @param count
*/
@Transactional(rollbackFor = Exception.class)
public void deduct(String commodityCode, int count) {
if (commodityCode.equals("product-2")) {
throw new RuntimeException("異常:模擬業(yè)務(wù)異常:stock branch exception");
}
QueryWrapper<Stock> wrapper = new QueryWrapper<>();
wrapper.setEntity(new Stock().setCommodityCode(commodityCode));
Stock stock = stockDAO.selectOne(wrapper);
stock.setCount(stock.getCount() - count);
stock.setUpdateTime(new Date());
stockDAO.updateById(stock);
}
}
- controller
import com.cccc.service.StockService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("stock")
public class StockController {
@Resource
private StockService stockService;
/**
* 減庫存
*
* @param commodityCode 商品代碼
* @param count 數(shù)量
* @return
*/
@RequestMapping(path = "/deduct")
public Boolean deduct(String commodityCode, Integer count) {
stockService.deduct(commodityCode, count);
return true;
}
}
2.3. rm-order
- pom.xml
<parent>
<artifactId>springboot-openfeign-seataat</artifactId>
<groupId>com.cccc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rm-order</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>${spring.cloud.alibaba.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
<!-- mybatis -->
<!--mybatis-generator-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
<!--mybatis-generator-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>11.8</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
- applicaion.properties
spring.application.name=order-service
server.port=9092
# Nacos 注冊中心地址
spring.cloud.nacos.discovery.server-addr = xx.xx.xx.xx:8848
spring.cloud.nacos.discovery.namespace = nnnnn
spring.cloud.nacos.discovery.register-enabled = true
spring.cloud.nacos.discovery.username = uuuuu
spring.cloud.nacos.discovery.password=ppppp
spring.cloud.nacos.discovery.group=SEATA_GROUP
# 數(shù)據(jù)源配置
spring.datasource.url=jdbc:mysql://xx.xx.xx.xx:3306/seata_order?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=uuuuu
spring.datasource.password=ppppp
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#事務(wù)分組配置(在v1.5之后默認(rèn)值為default_tx_group)
seata.tx-service-group=seata-storage-service
#指定事務(wù)分組至集群映射關(guān)系(等號右側(cè)的集群名需要與Seata-server注冊到Nacos的cluster保持一致)
seata.service.vgroup-mapping.seata-storage-service=default
#使用nacos作為注冊中心
seata.registry.type=nacos
#nacos注冊中心IP:端口
seata.registry.nacos.server-addr=xx.xx.xx.xx:8848
seata.registry.nacos.username = uuuuu
seata.registry.nacos.password = ppppp
seata.registry.nacos.namespace = nnnnn
seata.registry.nacos.cluster = default
#Seata服務(wù)名(應(yīng)與seata-server實(shí)際注冊的服務(wù)名一致)
seata.registry.nacos.application=seata-server
#Seata分組名(應(yīng)與seata-server實(shí)際注冊的分組名一致)
seata.registry.nacos.group=SEATA_GROUP
logging.level.io.seata=debug
3.啟動類
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
- 實(shí)體類
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.Date;
@Data
@Accessors(chain = true)
@TableName("order_tbl")
public class Order {
@TableId(type = IdType.AUTO)
private Integer id;
private String userId;
private String commodityCode;
private Integer count;
private BigDecimal money;
private Date createTime;
}
- dao
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cccc.model.Order;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface OrderDAO extends BaseMapper<Order> {
}
- service
import com.cccc.model.Order;
import com.cccc.repository.OrderDAO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
@Service
public class OrderService {
@Resource
private OrderDAO orderDAO;
/**
* 創(chuàng)建訂單
*
* @param userId
* @param commodityCode
* @param count
*/
@Transactional(rollbackFor = Exception.class)
public void placeOrder(String userId, String commodityCode, Integer count) {
BigDecimal orderMoney = new BigDecimal(count).multiply(new BigDecimal(5));
Order order = new Order().setUserId(userId).setCommodityCode(commodityCode).setCount(count)
.setMoney(orderMoney).setCreateTime(new Date());
orderDAO.insert(order);
}
}
- controller
import com.cccc.service.OrderService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("order")
public class OrderController {
@Resource
private OrderService orderService;
/**
* 下單:插入訂單表瞒爬、扣減庫存,模擬回滾
*
* @return
*/
@RequestMapping("/placeOrder/commit")
public Boolean placeOrderCommit(String userId, String commodityCode, Integer count) {
orderService.placeOrder(userId, commodityCode, count);
return true;
}
}
2.4. rm-portal
- pom.xml
<parent>
<artifactId>springboot-openfeign-seataat</artifactId>
<groupId>com.cccc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>tm-portal</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>${spring.cloud.alibaba.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>11.8</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
- applicaion.properties
spring.application.name=portal-service
server.port=9090
# Nacos 注冊中心地址
spring.cloud.nacos.discovery.server-addr = xx.xx.xx.xx:8848
spring.cloud.nacos.discovery.namespace = nnnnn
spring.cloud.nacos.discovery.register-enabled = true
spring.cloud.nacos.discovery.username = uuuuu
spring.cloud.nacos.discovery.password=ppppp
spring.cloud.nacos.discovery.group=SEATA_GROUP
#事務(wù)分組配置(在v1.5之后默認(rèn)值為default_tx_group)
seata.tx-service-group=seata-storage-service
#指定事務(wù)分組至集群映射關(guān)系(等號右側(cè)的集群名需要與Seata-server注冊到Nacos的cluster保持一致)
seata.service.vgroup-mapping.seata-storage-service=default
#使用nacos作為注冊中心
seata.registry.type=nacos
#nacos注冊中心IP:端口
seata.registry.nacos.server-addr=xx.xx.xx.xx:8848
seata.registry.nacos.username = uuuuu
seata.registry.nacos.password = ppppp
seata.registry.nacos.namespace = nnnnn
seata.registry.nacos.cluster = default
#Seata服務(wù)名(應(yīng)與seata-server實(shí)際注冊的服務(wù)名一致)
seata.registry.nacos.application=seata-server
#Seata分組名(應(yīng)與seata-server實(shí)際注冊的分組名一致)
seata.registry.nacos.group=SEATA_GROUP
logging.level.io.seata=debug
3.啟動類
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class PortalApplication {
public static void main(String[] args) {
SpringApplication.run(PortalApplication.class, args);
}
}
- feign
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "order-service")
public interface OrderFeignClient {
@GetMapping("order/placeOrder/commit")
Boolean placeOrderCommit(@RequestParam("userId") String userId, @RequestParam("commodityCode") String commodityCode, @RequestParam("count") Integer count);
}
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "stock-service")
public interface StockFeignClient {
@GetMapping("stock/deduct")
Boolean deduct(@RequestParam("commodityCode") String commodityCode, @RequestParam("count") Integer count);
}
- service
import com.cccc.feign.OrderFeignClient;
import com.cccc.feign.StockFeignClient;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class PortalService {
@Resource
private StockFeignClient stockFeignClient;
@Resource
private OrderFeignClient orderFeignClient;
/**
* 下單:創(chuàng)建訂單沟堡、減庫存侧但,涉及到兩個(gè)服務(wù)
*
* @param userId
* @param commodityCode
* @param count
*/
@GlobalTransactional
public void placeOrder(String userId, String commodityCode, Integer count) {
orderFeignClient.placeOrderCommit(userId, commodityCode, count);
stockFeignClient.deduct(commodityCode, count);
}
/**
* 下單:創(chuàng)建訂單、減庫存弦叶,涉及到兩個(gè)服務(wù)
*
* @param userId
* @param commodityCode
* @param count
*/
public void placeOrder2(String userId, String commodityCode, Integer count) {
orderFeignClient.placeOrderCommit(userId, commodityCode, count);
stockFeignClient.deduct(commodityCode, count);
}
}
- controller
import com.cccc.service.PortalService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("portal")
public class PortalController {
@Resource
private PortalService portalService;
/**
* 下單:插入訂單表俊犯、扣減庫存,模擬回滾
*
* @return
*/
@RequestMapping("/commit")
public Boolean placeOrderCommit() {
portalService.placeOrder("1", "product-1", 1);
return true;
}
/**
* 下單:插入訂單表伤哺、扣減庫存,模擬回滾
*
* @return
*/
@RequestMapping("/rollback")
public Boolean placeOrderRollback() {
// product-2 扣庫存時(shí)模擬了一個(gè)業(yè)務(wù)異常,
portalService.placeOrder("1", "product-2", 1);
return true;
}
/**
* 下單:插入訂單表者祖、扣減庫存立莉,模擬回滾
*
* @return
*/
@RequestMapping("/commit2")
public Boolean placeOrderCommit2() {
portalService.placeOrder2("1", "product-1", 1);
return true;
}
/**
* 下單:插入訂單表、扣減庫存七问,模擬回滾
*
* @return
*/
@RequestMapping("/rollback2")
public Boolean placeOrderRollback2() {
// product-2 扣庫存時(shí)模擬了一個(gè)業(yè)務(wù)異常,
portalService.placeOrder2("1", "product-2", 1);
return true;
}
}
3. 演示
3.1. 運(yùn)行rm-order蜓耻、rm-stock、tm-portal
3.2. tm-portal提供4個(gè)url
-
http://localhost:9090/portal/commit
開分布式事務(wù)械巡,下單成功刹淌,扣除商品成功。order_tbl表有新記錄讥耗,stock_tbl表商品數(shù)量減少 -
http://localhost:9090/portal/rollback
開分布式事務(wù)有勾,下單成功,扣除商品拋異常古程。order_tbl表無新記錄蔼卡,stock_tbl表商品數(shù)量不變
rm-order、rm-stock的數(shù)據(jù)庫操作都回滾掉了 -
http://localhost:9090/portal/commit2
不開分布式事務(wù)挣磨,下單成功雇逞,扣除商品成功荤懂。order_tbl表有新記錄,stock_tbl表商品數(shù)量減少 -
http://localhost:9090/portal/rollback2
不開分布式事務(wù)塘砸,下單成功节仿,扣除商品拋異常。order_tbl表有新記錄掉蔬,stock_tbl表商品數(shù)量不變
rm-order的數(shù)據(jù)庫操作沒有回滾掉了
對比2和4廊宪,可以看出seata的分布式事務(wù)效果