springcloud-nacos-seata
分布式事务组件seata的使用demo,AT模式,集成nacos、springboot、springcloud、mybatis-plus,数据库采用mysql
demo中使用的相关版本号,具体请看代码。如果搭建个人demo不成功,验证是否是由版本导致,由于目前这几个项目更新比较频繁,版本稍有变化便会出现许多奇怪问题
- seata 1.4.2
- spring-cloud-alibaba-seata 2.1.0.RELEASE
- spring-cloud-starter-alibaba-nacos-discovery 0.2.1.RELEASE
- springboot 2.0.6.RELEASE
- springcloud Finchley.RELEASE
1. 服务端配置
1.1 Nacos-server
版本为nacos-server-2.0.4,demo采用本地单机部署方式,请参考 Nacos 快速开始
1.2 Seata-server
seata-server为release版本1.4.2,demo采用本地单机部署,从此处下载 https://github.com/seata/seata/releases
并解压
1.2.1 修改conf/registry.conf 配置
设置type、设置serverAddr为你的nacos节点地址。
注意这里有一个坑,serverAddr不能带‘http://’前缀
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
serverAddr = "127.0.0.1"
namespace = ""
cluster = "default"
}
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "127.0.0.1"
namespace = ""
cluster = "default"
}
}
1.2.2 修改conf/nacos-config.txt 配置
service.vgroup_mapping.${your-service-gruop}=default,中间的${your-service-gruop}为自己定义的服务组名称,服务中的application.properties文件里配置服务组名称。
demo中有两个服务,分别是stock-service和order-service,所以配置如下
service.vgroup_mapping.stock-service-group=default
service.vgroup_mapping.order-service-group=default
** 注意这里,高版本中应该是vgroupMapping 同时后面的如: order-service-group 不能定义为 order_service_group**
1.3 启动seata-server
分两步,如下
# 初始化seata 的nacos配置
cd conf
sh nacos-config.sh 127.0.0.1
# 启动seata-server
cd bin
sh seata-server.sh -p 8091 -m file
2. 应用配置
2.1 数据库初始化
-- 创建 order库、业务表、undo_log表
create database seata_order;
use seata_order;
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;
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;
-- 创建 stock库、业务表、undo_log表
create database seata_stock;
use seata_stock;
DROP TABLE IF EXISTS `stock_tbl`;
CREATE TABLE `stock_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;
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;
-- 初始化库存模拟数据
INSERT INTO seata_stock.stock_tbl (id, commodity_code, count) VALUES (1, 'product-1', 9999999);
INSERT INTO seata_stock.stock_tbl (id, commodity_code, count) VALUES (2, 'product-2', 0);
2.2 应用配置
见代码
几个重要的配置
- 每个应用的resource里需要配置一个registry.c ,demo中与seata-server里的配置相同
- application.propeties 的各个配置项,注意spring.cloud.alibaba.seata.tx-service-group 是服务组名称,与nacos-config.txt
配置的service.vgroup_mapping.${your-service-gruop}具有对应关系
3. 测试
-
分布式事务成功,模拟正常下单、扣库存
localhost:9091/order/placeOrder/commit
-
分布式事务失败,模拟下单成功、扣库存失败,最终同时回滚
localhost:9091/order/placeOrder/rollback
相关代码
order模块
/**
* 下单:创建订单、减库存,涉及到两个服务
*
* @param userId
* @param commodityCode
* @param count
*/
@GlobalTransactional
@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);
orderDAO.insert(order);
stockFeignClient.deduct(commodityCode, count);
}
stock模块
/**
* 减库存
*
* @param commodityCode
* @param count
*/
@Transactional(rollbackFor = Exception.class)
public void deduct(String commodityCode, int count) {
if (commodityCode.equals("product-2")) {
throw new RuntimeException("异常:模拟业务异常:stock branch exception");
}
QueryWrapper<Stock> wrapper = new QueryWrapper<>();
wrapper.setEntity(new Stock().setCommodityCode(commodityCode));
Stock stock = stockDAO.selectOne(wrapper);
stock.setCount(stock.getCount() - count);
stockDAO.updateById(stock);
}
标签:事务,seata,nacos,分布式,order,NULL,id,stock
From: https://www.cnblogs.com/lori/p/17875453.html