提交 deac4ac9 编写于 作者: zlt2000's avatar zlt2000

增加seata-demo工程

上级 6632da7b
...@@ -16,5 +16,7 @@ ...@@ -16,5 +16,7 @@
<module>sharding-jdbc-demo</module> <module>sharding-jdbc-demo</module>
<!-- rocketmq消息队列demo --> <!-- rocketmq消息队列demo -->
<module>rocketmq-demo</module> <module>rocketmq-demo</module>
<!-- seata分布式事务demo -->
<module>seata-demo</module>
</modules> </modules>
</project> </project>
\ No newline at end of file
[TOC]
## 一、说明
**包括以下5个模块,分别是**
* `business-service`:业务服务
* `storage-service`:库存服务
* `order-service`:订单服务
* `account-service`:账号服务
* `seata-common-starter`:公共工程
&nbsp;
**本demo主要是模拟用户下订单的场景,整个流程如下:**
用户下单(`business-service`) -> 扣库存(`storage-service`) -> 创建订单(`order-service`) -> 减少账户余额(`account-service`)
&nbsp;
**提供以下两个测试接口**
1. `http://localhost:9090/placeOrder`:成功下单
2. `http://localhost:9090/placeOrder`:测试异常回滚,`storage-service``order-service`的事务已提交,`account-service`出异常后全局回滚
&nbsp;
## 二、运行步骤
### 2.1. 部署运行seata-server
`seata`的注册中心和配置中心需改成`nacos`
**下载地址:**https://github.com/seata/seata/releases
### 2.2. 初始化demo的数据库脚本
[seata-demo.sql](seata-demo.sql)
### 2.3. 修改各个服务的配置
* 修改`bootstrap.yml`中的nacos地址
* 修改`application.yml`中的数据库配置
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zlt</groupId>
<artifactId>seata-demo</artifactId>
<version>2.6.0</version>
</parent>
<artifactId>account-service</artifactId>
<dependencies>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>seata-common-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package com.central.account;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* 账号
*
* @author zlt
* @date 2019/9/14
*/
@EnableDiscoveryClient
@MapperScan({"com.central.account.mapper"})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class AccountServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AccountServiceApplication.class, args);
}
}
package com.central.account.controller;
import com.central.account.service.AccountService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author zlt
* @date 2019/9/14
*/
@Slf4j
@RestController
public class AccountController {
@Resource
private AccountService accountService;
/**
* 账号扣钱
*/
@PostMapping(value = "/account/reduce")
public Boolean reduce(String userId, Integer money) {
accountService.reduce(userId, money);
return true;
}
}
package com.central.account.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.central.account.model.Account;
/**
* @author zlt
* @date 2019/9/14
*/
public interface AccountMapper extends BaseMapper<Account> {
}
package com.central.account.model;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 账号
*
* @author zlt
* @date 2019/9/14
*/
@Data
@Accessors(chain = true)
@TableName("account_tbl")
public class Account {
@TableId
private Long id;
private String userId;
private Integer money;
}
package com.central.account.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.central.account.model.Account;
import com.central.account.mapper.AccountMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* @author zlt
* @date 2019/9/14
*/
@Slf4j
@Service
public class AccountService {
@Resource
private AccountMapper accountMapper;
/**
* 减账号金额
*/
//@Transactional(rollbackFor = Exception.class)
public void reduce(String userId, int money) {
if ("U002".equals(userId)) {
throw new RuntimeException("this is a mock Exception");
}
QueryWrapper<Account> wrapper = new QueryWrapper<>();
wrapper.setEntity(new Account().setUserId(userId));
Account account = accountMapper.selectOne(wrapper);
account.setMoney(account.getMoney() - money);
accountMapper.updateById(account);
}
}
spring:
datasource:
url: jdbc:mysql://192.168.28.130:3306/seata-demo?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull
username: root
password: 1q2w3e4r
driver-class-name: com.mysql.jdbc.Driver
cloud:
alibaba:
seata:
# seata 服务分组,要与服务端nacos-config.txt中service.vgroup_mapping的后缀对应,默认是${spring.application.name}-fescar-service-group
tx-service-group: account-service-group
\ No newline at end of file
server:
port: 9093
spring:
application:
name: account-service
cloud:
nacos:
discovery:
server-addr: 192.168.28.130:8848
\ No newline at end of file
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
serverAddr = "192.168.28.130"
namespace = "public"
cluster = "default"
}
file {
name = "file.conf"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "192.168.28.130"
namespace = "public"
cluster = "default"
}
file {
name = "file.conf"
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zlt</groupId>
<artifactId>seata-demo</artifactId>
<version>2.6.0</version>
</parent>
<artifactId>business-service</artifactId>
<dependencies>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>zlt-ribbon-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package com.central.business;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 业务
*
* @author zlt
* @date 2019/9/14
*/
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class BusinessServiceApplication {
public static void main(String[] args) {
SpringApplication.run(BusinessServiceApplication.class, args);
}
}
package com.central.business.controller;
import com.central.business.service.BusinessService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author zlt
* @date 2019/9/14
*/
@RestController
public class BusinessController {
@Resource
private BusinessService businessService;
/**
* 下单场景测试-正常
*/
@RequestMapping(path = "/placeOrder")
public Boolean placeOrder() {
businessService.placeOrder("U001");
return true;
}
/**
* 下单场景测试-回滚
*/
@RequestMapping(path = "/placeOrderFallBack")
public Boolean placeOrderFallBack() {
businessService.placeOrder("U002");
return true;
}
}
package com.central.business.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 订单
*
* @author zlt
* @date 2019/9/14
*/
@FeignClient(name = "order-service")
public interface OrderFeignClient {
@GetMapping("order/create")
Boolean create(@RequestParam("userId") String userId, @RequestParam("commodityCode") String commodityCode, @RequestParam("count") Integer count);
}
package com.central.business.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 库存
*
* @author zlt
* @date 2019/9/14
*/
@FeignClient(name = "storage-service")
public interface StorageFeignClient {
@GetMapping("storage/deduct")
Boolean deduct(@RequestParam("commodityCode") String commodityCode, @RequestParam("count") Integer count);
}
package com.central.business.service;
import com.central.business.feign.OrderFeignClient;
import com.central.business.feign.StorageFeignClient;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 业务
*
* @author zlt
* @date 2019/9/14
*/
@Slf4j
@Service
public class BusinessService {
private static final String COMMODITY_CODE = "P001";
private static final int ORDER_COUNT = 1;
@Resource
private OrderFeignClient orderFeignClient;
@Resource
private StorageFeignClient storageFeignClient;
/**
* 下订单
*/
@GlobalTransactional
public void placeOrder(String userId) {
storageFeignClient.deduct(COMMODITY_CODE, ORDER_COUNT);
orderFeignClient.create(userId, COMMODITY_CODE, ORDER_COUNT);
}
}
spring:
cloud:
alibaba:
seata:
# seata 服务分组,要与服务端nacos-config.txt中service.vgroup_mapping的后缀对应,默认是${spring.application.name}-fescar-service-group
tx-service-group: business-service-group
\ No newline at end of file
server:
port: 9090
spring:
application:
name: business-service
cloud:
nacos:
discovery:
server-addr: 192.168.28.130:8848
\ No newline at end of file
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
serverAddr = "192.168.28.130"
namespace = "public"
cluster = "default"
}
file {
name = "file.conf"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "192.168.28.130"
namespace = "public"
cluster = "default"
}
file {
name = "file.conf"
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zlt</groupId>
<artifactId>seata-demo</artifactId>
<version>2.6.0</version>
</parent>
<artifactId>order-service</artifactId>
<dependencies>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>seata-common-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>zlt-ribbon-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package com.central.order;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 订单
*
* @author zlt
* @date 2019/9/14
*/
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan({"com.central.order.mapper"})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
package com.central.order.controller;
import com.central.order.service.OrderService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 订单
*
* @author zlt
* @date 2019/9/14
*/
@RestController
@RequestMapping("order")
public class OrderController {
@Resource
private OrderService orderService;
/**
* 创建订单
* @param userId 用户id
* @param commodityCode 订单编号
* @param count 数量
*/
@RequestMapping("/create")
public Boolean create(String userId, String commodityCode, Integer count) {
orderService.create(userId, commodityCode, count);
return true;
}
}
package com.central.order.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author zlt
* @date 2019/9/14
*/
@FeignClient(name = "account-service")
public interface AccountFeignClient {
@PostMapping("account/reduce")
Boolean reduce(@RequestParam("userId") String userId, @RequestParam("money") Integer money);
}
package com.central.order.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.central.order.model.Order;
/**
* @author zlt
* @date 2019/9/14
*/
public interface OrderMapper extends BaseMapper<Order> {
}
package com.central.order.model;
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;
/**
* 订单
*
* @author zlt
* @date 2019/9/14
*/
@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 Integer money;
}
package com.central.order.service;
import com.central.order.mapper.OrderMapper;
import com.central.order.feign.AccountFeignClient;
import com.central.order.model.Order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* @author zlt
* @date 2019/9/14
*/
@Slf4j
@Service
public class OrderService {
@Resource
private AccountFeignClient accountFeignClient;
@Resource
private OrderMapper orderMapper;
//@Transactional(rollbackFor = Exception.class)
public void create(String userId, String commodityCode, Integer count) {
//订单金额
Integer orderMoney = count * 2;
Order order = new Order()
.setUserId(userId)
.setCommodityCode(commodityCode)
.setCount(count)
.setMoney(orderMoney);
orderMapper.insert(order);
accountFeignClient.reduce(userId, orderMoney);
}
}
spring:
datasource:
url: jdbc:mysql://192.168.28.130:3306/seata-demo?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull
username: root
password: 1q2w3e4r
driver-class-name: com.mysql.jdbc.Driver
cloud:
alibaba:
seata:
# seata 服务分组,要与服务端nacos-config.txt中service.vgroup_mapping的后缀对应,默认是${spring.application.name}-fescar-service-group
tx-service-group: order-service-group
\ No newline at end of file
server:
port: 9091
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 192.168.28.130:8848
\ No newline at end of file
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
serverAddr = "192.168.28.130"
namespace = "public"
cluster = "default"
}
file {
name = "file.conf"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "192.168.28.130"
namespace = "public"
cluster = "default"
}
file {
name = "file.conf"
}
}
<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>com.zlt</groupId>
<artifactId>zlt-demo</artifactId>
<version>2.6.0</version>
</parent>
<artifactId>seata-demo</artifactId>
<description>seata分布式事务demo</description>
<packaging>pom</packaging>
<modules>
<!-- 业务服务(TM) -->
<module>business-service</module>
<!-- 订单服务(RM) -->
<module>order-service</module>
<!-- 库存服务(RM) -->
<module>storage-service</module>
<!-- 账号服务(RM) -->
<module>account-service</module>
<!-- 通用配置 -->
<module>seata-common-starter</module>
</modules>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zlt</groupId>
<artifactId>seata-demo</artifactId>
<version>2.6.0</version>
</parent>
<artifactId>seata-common-starter</artifactId>
<dependencies>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>zlt-db-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- seata-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
</dependencies>
</project>
package com.central.common.config;
import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.*;
/**
* @author zlt
* @date 2019/9/14
*/
public class DataSourceProxyConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
@Primary
@Bean
public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
}
\ No newline at end of file
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.central.common.config.DataSourceProxyConfig
CREATE DATABASE `seata-demo` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE `seata-demo`;
--==========================回滚日志表==========================
-- the table to store seata xid data
-- 0.7.0+ add context
-- you must to init this sql for you business databese. the seata server not need it.
-- 此脚本必须初始化在你当前的业务数据库中,用于AT 模式XID记录。与server端无关(注:业务数据库)
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
drop table `undo_log`;
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) 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 AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
--==========================业务模拟表==========================
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 初始化库存模拟数据
INSERT INTO storage_tbl (id, commodity_code, count) VALUES (1, 'P001', 9999999);
INSERT INTO account_tbl (id, user_id, money) VALUES ('1', 'U001', 10000);
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zlt</groupId>
<artifactId>seata-demo</artifactId>
<version>2.6.0</version>
</parent>
<artifactId>storage-service</artifactId>
<dependencies>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>seata-common-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>zlt-ribbon-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package com.central.storage;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 库存
*
* @author zlt
* @date 2019/9/14
*/
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan({"com.central.storage.mapper"})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class StorageServiceApplication {
public static void main(String[] args) {
SpringApplication.run(StorageServiceApplication.class, args);
}
}
package com.central.storage.controller;
import com.central.storage.service.StorageService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 库存
*
* @author zlt
* @date 2019/9/14
*/
@RestController
@RequestMapping("storage")
public class StorageController {
@Resource
private StorageService storageService;
/**
* 减库存
* @param commodityCode 商品代码
* @param count 数量
*/
@RequestMapping(path = "/deduct")
public Boolean deduct(String commodityCode, Integer count) {
storageService.deduct(commodityCode, count);
return true;
}
}
package com.central.storage.mapper;
import com.central.db.mapper.SuperMapper;
import com.central.storage.model.Storage;
/**
* @author zlt
* @date 2019/9/14
*/
public interface StorageMapper extends SuperMapper<Storage> {
}
package com.central.storage.model;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 库存
*
* @author zlt
* @date 2019/9/14
*/
@Data
@Accessors(chain = true)
@TableName("storage_tbl")
public class Storage {
@TableId
private Long id;
private String commodityCode;
private Long count;
}
package com.central.storage.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.central.storage.model.Storage;
import com.central.storage.mapper.StorageMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* @author zlt
* @date 2019/9/14
*/
@Slf4j
@Service
public class StorageService {
@Resource
private StorageMapper storageMapper;
/**
* 减库存
*
* @param commodityCode 商品编号
* @param count 数量
*/
//@Transactional(rollbackFor = Exception.class)
public void deduct(String commodityCode, int count) {
QueryWrapper<Storage> wrapper = new QueryWrapper<>();
wrapper.setEntity(new Storage().setCommodityCode(commodityCode));
Storage storage = storageMapper.selectOne(wrapper);
storage.setCount(storage.getCount() - count);
storageMapper.updateById(storage);
}
}
spring:
datasource:
url: jdbc:mysql://192.168.28.130:3306/seata-demo?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull
username: root
password: 1q2w3e4r
driver-class-name: com.mysql.jdbc.Driver
cloud:
alibaba:
seata:
# seata 服务分组,要与服务端nacos-config.txt中service.vgroup_mapping的后缀对应,默认是${spring.application.name}-fescar-service-group
tx-service-group: storage-service-group
\ No newline at end of file
server:
port: 9092
spring:
application:
name: storage-service
cloud:
nacos:
discovery:
server-addr: 192.168.28.130:8848
\ No newline at end of file
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
serverAddr = "192.168.28.130"
namespace = "public"
cluster = "default"
}
file {
name = "file.conf"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "192.168.28.130"
namespace = "public"
cluster = "default"
}
file {
name = "file.conf"
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册