Spring Cloud Alibaba:Seata基础知识
介绍
Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
分布式事务处理过程一ID+三组件模型:
Transaction ID XID 全局唯一的事务ID
三组件:
TC (Transaction Coordinator) – 事务协调者:维护全局和分支事务的状态,驱动全局事务提交或回滚。
TM (Transaction Manager) – 事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务。
RM (Resource Manager) – 资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
Seata处理过程:
1.TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID.
2.XID在微服务调用链路的上下文中传播。
3.RM向TC注册分支事务,将其纳入XID对应全局事务的管辖。
4.TM向TC发起针对XID的全局提交或回滚决议。
5.TC调度XID下管辖的全部分支事务完成提交或回滚请求。
安装
从github上下载seata-server09的zip包,解压之后,进入conf目录,修改配置文件file.conf
然后在本机创建seata数据库,并执行conf目录下的db_store.sql文件
修改register.conf配置文件,修改注册中心为nacos,并配置连接地址,双击bin目录下的seata-server.bat.
建库
CREATE DATABASE seata_order;
USE seata_order;
CREATE TABLE t_order(
id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
user_id BIGINT(11) DEFAULT NULL COMMENT ‘用户id‘,
product_id BIGINT(11) DEFAULT NULL COMMENT ‘产品id‘,
count INT(11) DEFAULT NULL COMMENT ‘数量‘,
money DECIMAL(11,0) DEFAULT NULL COMMENT ‘金额‘,
status INT(1) DEFAULT NULL COMMENT ‘订单状态:0创建中,1已完结‘
)ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;
INSERT INTO `seata_order`.`t_order` (`id`, `user_id`, `product_id`, `count`, `money`, `status`) VALUES (‘51‘, ‘1‘, ‘1‘, ‘10‘, ‘100‘, ‘1‘);
INSERT INTO `seata_order`.`t_order` (`id`, `user_id`, `product_id`, `count`, `money`, `status`) VALUES (‘52‘, ‘1‘, ‘1‘, ‘10‘, ‘100‘, ‘1‘);
INSERT INTO `seata_order`.`t_order` (`id`, `user_id`, `product_id`, `count`, `money`, `status`) VALUES (‘54‘, ‘1‘, ‘1‘, ‘10‘, ‘100‘, ‘1‘);
INSERT INTO `seata_order`.`t_order` (`id`, `user_id`, `product_id`, `count`, `money`, `status`) VALUES (‘55‘, ‘1‘, ‘1‘, ‘10‘, ‘100‘, ‘0‘);
CREATE DATABASE seata_storage;
USE seata_storage;
CREATE TABLE t_storage(
id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
product_id BIGINT(11) DEFAULT NULL COMMENT ‘产品id‘,
total INT(11) DEFAULT NULL COMMENT ‘总库存‘,
used INT(11) DEFAULT NULL COMMENT ‘已用库存‘,
residue INT(11) DEFAULT NULL COMMENT ‘剩余库存‘
)ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;
INSERT INTO t_storage(id, product_id, total, used, residue) VALUES(1,1,100,0,100);
CREATE DATABASE seata_account;
USE seata_account;
CREATE TABLE t_account(
id BIGINT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
user_id BIGINT(11) DEFAULT NULL COMMENT ‘用户id‘,
total DECIMAL(10,0) DEFAULT NULL COMMENT ‘总额度‘,
used DECIMAL(10,0) DEFAULT NULL COMMENT ‘已用额度‘,
residue DECIMAL(10,0) DEFAULT 0 COMMENT ‘剩余可用额度‘
)ENGINE=InnoDB AUTO_INCREMENT=7 CHARSET=utf8;
INSERT INTO t_account(id, user_id, total, used, residue) VALUES(1,1,1000,0,1000);
建完三个数据库后,分别在三个库中执行conf目录下的db_undo_log.sql回滚表
总计:
搭建微服务
业务需求:下订单->减库存->扣余额->改订单状态
三个微服务只示范订单微服务:
pom依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<exclusions>
<exclusion>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置文件:
server:
port: 2001
spring:
application:
name: seata-order-service
cloud:
alibaba:
seata:
#事务组的名称,与file.conf中的组名相同
tx-service-group: wj_group
nacos:
discovery:
server-addr: 192.168.10.137:8848
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/seata_order
username: root
password: 1234
logging:
level:
io:
seata: info
mybatis:
mapperLocations: classpath:mapper/*.xml
主启动类:
@MapperScan("com.wj.springcloud.dao")
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDiscoveryClient
@EnableFeignClients
public class SeataOrderMainApp2001 {
public static void main(String[] args) {
SpringApplication.run(SeataOrderMainApp2001.class,args);
}
}
配置类:
@Configuration
public class DataSourceProxyConfig {
@Value("${mybatis.mapperLocations}")
private String mapperLocations;
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource() {
return new DruidDataSource();
}
@Bean
public DataSourceProxy dataSourceProxy(DataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSourceProxy);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
bean.setMapperLocations(resolver.getResources(mapperLocations));
return bean.getObject();
}
}
service,controller和mapper以及mapper.xml省略
使用@GlobalTransactional注解开启分布式事务
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private AccountService accountService;
@Autowired
private StorageService storageService;
@Override
@GlobalTransactional
public void create(Order order) {
log.info("---->开始新建订单");
orderDao.create(order);
log.info("---->订单微服务开始调用库存,做扣减");
storageService.decrease(order.getProductId(),order.getCount());
log.info("---->订单微服务开始调用账户,做扣减");
accountService.decrease(order.getUserId(),order.getMoney());
log.info("---->修改订单状态");
orderDao.update(order.getUserId(),0);
log.info("下订单结束");
}
}
@Component
@FeignClient(value="seata-account-service")
public interface AccountService {
@PostMapping("/account/decrease")
CommonResult decrease(@RequestParam("userId") Long userId, @RequestParam("count") BigDecimal count);
}
@Component
@FeignClient(value="seata-storage-service")
public interface StorageService {
@PostMapping("/storage/decrease")
CommonResult decrease(@RequestParam("productId") Long productId,@RequestParam("count") Integer count);
}
以往所有SpringCloud代码已上传至github:https://github.com/JGZY/cloud2020
Spring Cloud Alibaba:Seata基础知识
原文:https://www.cnblogs.com/wwjj4811/p/13640693.html