springboot2整合seata(AT模式)

1.启动seata服务

docker启动seata-server实例,使用1.3.0版本

docker pull seataio/seata-server:1.3.0
docker run --name seata-server -p 8091:8091 seataio/seata-server

2.创建三个项目实现下订单、库存减少分布式事物

dkn-provider-order 下订单服务
dkn-provider-store 库存服务
dkn-shop 模拟用户购买商品服务

1.dkn-provider-orde和dkn-provider-store的pom.xml

<dependencyManagement>
  <dependencies>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.2.3.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.3.8.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Hoxton.SR8</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
</dependencies>
</dependencyManagement>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.2</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-seata</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

2.yml配置文件 dkn-provider-orde和dkn-provider-store

端口,服务名称、数据库信息,application-id需要换下

server:
  port: 9102
spring:
  application:
    name: dkn-provider-order
  datasource:
    druid:
      url: jdbc:mysql://localhost:3306/dkn-provider-order?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
      driverClassName: com.mysql.cj.jdbc.Driver
      username: root
      password: root

seata:
  enabled: true
  application-id: dkn-provider-order
  tx-service-group: dkn_tx_group
  enable-auto-data-source-proxy: false   #一定要是false
  service:
    vgroup-mapping:
      dkn_tx_group: default  #key与上面的tx-service-group的值对应
    grouplist:
      default: 10.0.0.70:8091 #seata-server地址仅file注册中心需要
  config:
    type: file
  registry:
    type: file

logging:
  level:
    com.dkn: debug

3.SeataConfig配置,这个都一样,dkn-shop不需要添加

@Configuration
public class SeataConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.druid")
    public DataSource druidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        return druidDataSource;
    }

    @Primary
    @Bean("dataSource")
    public DataSourceProxy dataSource(DataSource druidDataSource){
        return new DataSourceProxy(druidDataSource);
    }

}

4.service和controller

@Service
public class DknOrderServiceImpl extends ServiceImpl<DknOrderMapper,DknOrder> implements DknOrderService {

    @Override
    public boolean add(Integer productid, Integer num) {
        DknOrder dknOrder=new DknOrder();
        dknOrder.setNum(num);
        dknOrder.setProductid(productid);

        return this.save(dknOrder);
    }
}
@Service
public class StoreServiceImpl extends ServiceImpl<StoreMapper,Store> implements StoreService {

    @Override
    public boolean reduce(Integer productid,Integer n) {
        UpdateWrapper<Store> updateWrapper=new UpdateWrapper<Store>();
        updateWrapper.setSql("num = num - "+n);
        updateWrapper.eq("productid", productid);
        return this.update(updateWrapper);
    }
}
@RestController
@RequestMapping("/Order")
public class DknOrderController {

	@Autowired
	private DknOrderService dknOrderService;

	@GetMapping("add")
	public AjaxResult add(Integer productid, Integer num){
		boolean result=dknOrderService.add(productid,num);
		if(result){
			return AjaxResult.success();
		}else{
			return AjaxResult.error();
		}
	}
	
}
@RestController
@RequestMapping("/Store")
public class StoreController {

	@Autowired
	private StoreService storeService;
	
	@GetMapping("reduce")
	public AjaxResult reduce(Integer productid,Integer num){
		boolean result=storeService.reduce(productid,num);
		if(result){
			return AjaxResult.success();
		}else{
			return AjaxResult.error();
		}
	}

}
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class StoreApplication {
    public static void main(String[] args) {
        SpringApplication.run(StoreApplication.class, args);
    }
}

5.dkn-shop配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-seata</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>
server:
  port: 9100
spring:
  application:
    name: dkn-shop

seata:
  enabled: true
  application-id: dkn-shop
  tx-service-group: dkn_tx_group
  enable-auto-data-source-proxy: false   #一定要是false
  service:
    vgroup-mapping:
      dkn_tx_group: default  #key与上面的tx-service-group的值对应
    grouplist:
      default: 10.0.0.70:8091 #seata-server地址仅file注册中心需要
  config:
    type: file
  registry:
    type: file

#开启使用 httpclient
feign:
  httpclient:
    enabled: true

logging:
  level:
    com.dkn: debug
    org.apache.http: debug
@EnableFeignClients
@SpringBootApplication
public class ShopApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShopApplication.class, args);
    }
}
@FeignClient(name="dkn-provider-order", url = "http://localhost:9102")
@Service
public interface OrderService {
    @GetMapping("/Order/add")
    public AjaxResult add(@RequestParam(name = "productid") Integer productid, @RequestParam(name = "num") Integer num);

}
@FeignClient(name="dkn-provider-store", url = "http://localhost:9101")
@Service
public interface StoreService {
    @GetMapping("/Store/reduce")
    public AjaxResult reduce(@RequestParam(name = "productid") Integer productid, @RequestParam(name = "num") Integer num);

}
@Service
public class ShopService {

    @Autowired
    OrderService orderService;

    @Autowired
    StoreService storeService;

    @GlobalTransactional
    public void buy(Integer productid,Integer num){
        orderService.add(productid,num);
        storeService.reduce(productid,num);
    }

    @GlobalTransactional
    public void buyError(Integer productid,Integer num){
        orderService.add(productid,num);
        int a=1/0;
        storeService.reduce(productid,num);
    }

}
@RestController
@RequestMapping("/Shop")
public class ShopController {

	@Autowired
	private ShopService shopService;

	//测试正常  http://localhost:9100/Shop/buy?productid=101&num=2
	@GetMapping("buy")
	public AjaxResult buy(Integer productid, Integer num){
		shopService.buy(productid,num);
		return AjaxResult.success();
	}

	//测试错误  http://localhost:9100/Shop/buy?productid=101&num=2
	@GetMapping("buyError")
	public AjaxResult buyError(Integer productid, Integer num){
		shopService.buyError(productid,num);
		return AjaxResult.success();
	}
}

6.数据库文件

-- ----------------------------
-- Table structure for store
-- ----------------------------
DROP TABLE IF EXISTS `store`;
CREATE TABLE `store` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `productid` int(11) DEFAULT NULL COMMENT '商品id',
  `productname` varchar(255) DEFAULT NULL COMMENT '商品名称',
  `num` int(11) DEFAULT NULL COMMENT '库存数量',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of store
-- ----------------------------
INSERT INTO `store` VALUES ('1', '101', '笔记本', '100');

-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `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=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of undo_log
-- ----------------------------
-- ----------------------------
-- Table structure for dkn_order
-- ----------------------------
DROP TABLE IF EXISTS `dkn_order`;
CREATE TABLE `dkn_order` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `productid` int(11) DEFAULT NULL COMMENT '商品id',
  `num` int(11) DEFAULT NULL COMMENT '购买数量',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of dkn_order
-- ----------------------------

-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `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=14 DEFAULT CHARSET=utf8;

posted @ 2021-02-20 01:08  dkn  阅读(282)  评论(0编辑  收藏  举报