seata实现分布式事务demo

seata是阿里开源的一款分布式事务中间件,有关seata的详细介绍可以查看seata的官方文档:http://seata.io/zh-cn/docs/user/configurations.html

这里我们来用官方的demo来实现seata的分布式事务。我们在此采用的是AT事务模式。实现分布式事务首先我们的服务得是分布式的,这里我们用dubbo框架+nacos作为注册中心。

nacos注册中心的搭建大家可以参考官方文档:https://nacos.io/zh-cn/docs/what-is-nacos.html。搭建后nacos官方文档之后,接下来就要搭建seata服务了,分布式事务的核心就是这个seata服务,相关搭建可以参考官方文档:http://seata.io/zh-cn/docs/user/quickstart.html。搭建seata服务首先要在数据库中创建undo_log表。seata的配置文件中配置好nacos的注册中心的地址以及mysql数据库的配置。

undo_log建表语句:

-- 注意此处0.3.0+ 增加唯一索引 ux_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;

数据库的配置在conf目录下的file.conf,这里我们使用的是mysql数据库所以配置好mysql数据库的配置:

db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
    datasource = "druid"
    ## mysql/oracle/postgresql/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    ## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param
    url = "jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&rewriteBatchedStatements=true"
    user = ""
    password = ""
    minConn = 5
    maxConn = 100
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
    maxWait = 5000
  }

nacos注册中心的配置在conf目录下的registry.conf配置文件中配置,这里我们使用的是nacos做为配置中心,所以配置好nacos。

nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "SEATA_GROUP"
    namespace = ""
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }

搭建好相关服务之后,我们就来下载github上的官方demo:https://github.com/seata/seata-samples

我们使用的是springboot-dubbo-seata这个demo,其结构目录如下

--springboot-dubbo-seata

--samples-account

--samples-business

--samples-common

--samples-order

--samples-storage

使用主类使用@EnableTransactionManagement注解为服务开启分布式事务,业务逻辑中使用@GlobalTransactional声明方法启用分布式事务。

主要业务逻辑在samples-business中如下所示:

@GlobalTransactional(timeoutMills = 300000, name = "dubbo-gts-seata-example")
    public ObjectResponse handleBusiness(BusinessDTO businessDTO) {
        System.out.println("开始全局事务,XID = " + RootContext.getXID());
        ObjectResponse<Object> objectResponse = new ObjectResponse<>();
        //1、扣减库存
        CommodityDTO commodityDTO = new CommodityDTO();
        commodityDTO.setCommodityCode(businessDTO.getCommodityCode());
        commodityDTO.setCount(businessDTO.getCount());
        ObjectResponse storageResponse = storageDubboService.decreaseStorage(commodityDTO);
        //2、创建订单
        OrderDTO orderDTO = new OrderDTO();
        orderDTO.setUserId(businessDTO.getUserId());
        orderDTO.setCommodityCode(businessDTO.getCommodityCode());
        orderDTO.setOrderCount(businessDTO.getCount());
        orderDTO.setOrderAmount(businessDTO.getAmount());
        ObjectResponse<OrderDTO> response = orderDubboService.createOrder(orderDTO);

        //打开注释测试事务发生异常后,全局回滚功能
        flag = false;
        if (!flag) {
            throw new RuntimeException("测试抛异常后,分布式事务回滚!");
        }

        if (storageResponse.getStatus() != 200 || response.getStatus() != 200) {
            throw new DefaultException(RspStatusEnum.FAIL);
        }

        objectResponse.setStatus(RspStatusEnum.SUCCESS.getCode());
        objectResponse.setMessage(RspStatusEnum.SUCCESS.getMessage());
        objectResponse.setData(response.getData());
        return objectResponse;
    }

handleBusiness方法调用samples-storage服务的减库存方法decreaseStorage()和samples-order服务的新增订单方法createOrder()。此处代码中的如下是用来模拟事务回滚,抛出异常。如果将此代码注释,在减库存和增订单的操作会执行成功。

flag = false;
if (!flag) {
    throw new RuntimeException("测试抛异常后,分布式事务回滚!");
}

业务代码mysql数据库脚本:

CREATE TABLE `t_order` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单ID',
  `order_no` varchar(32) DEFAULT NULL COMMENT '订单编号',
  `user_id` varchar(32) DEFAULT NULL COMMENT '用户ID',
  `commodity_code` varchar(32) DEFAULT NULL COMMENT '商品编号',
  `count` int(11) DEFAULT '0' COMMENT '数量',
  `amount` double DEFAULT '0.00' COMMENT '数量',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;


CREATE TABLE `t_storage` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '库存ID',
  `commodity_code` varchar(32) DEFAULT NULL COMMENT '商品编号',
  `name` varchar(32) DEFAULT NULL COMMENT '商品名称',
  `count` int(11) DEFAULT '0' COMMENT '库存数量',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;

CREATE TABLE `t_account` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '账户ID',
  `user_id` varchar(32) DEFAULT NULL COMMENT '用户ID',
  `amount` double DEFAULT '0.00' COMMENT '数量',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;

相关资料查阅:

http://seata.io/zh-cn/docs/user/quickstart.html

http://seata.io/zh-cn/docs/user/quickstart.html

https://mp.weixin.qq.com/s/2EeJU4569jOvyluRhrgdzQ

https://zhuanlan.zhihu.com/p/183753774

https://github.com/seata

https://blog.csdn.net/hosaos/article/details/90050276

在Spring Cloud Alibaba中使用Seata进行分布式事务,需要进行以下步骤: 1. 引入Seata依赖 在pom.xml文件中引入Seata的依赖: ``` <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <version>2.2.0.RELEASE</version> </dependency> ``` 2. 配置Seata 在application.yml文件中配置Seata的相关参数,包括: - 服务端配置 ``` spring: cloud: alibaba: seata: tx-service-group: my_test_tx_group # Seata事务组名称 service: vgroup-mapping: my_test_tx_group: default # Seata服务组名称 group-id: default # Seata服务分组ID config: type: file # Seata配置类型 file: name: file.conf # Seata配置文件名称 path: /seata/config # Seata配置文件路径 ``` - 客户端配置 ``` mybatis: configuration: # 启用二级缓存 cache-enabled: true # 数据源配置 type-aliases-package: com.example.demo.entity mapper-locations: classpath:mapper/*.xml configuration-properties: # 自动驼峰转换 mapUnderscoreToCamelCase: true # 数据库连接池配置 druid: url: jdbc:mysql://localhost:3306/seata?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver # Seata配置 seata: enabled: true # 启用Seata application-id: seata-demo # 应用ID tx-service-group: my_test_tx_group # Seata事务组名称 service: vgroup-mapping: my_test_tx_group: default # Seata服务组名称 # 注册中心配置 registry: type: nacos # 注册中心类型 nacos: server-addr: localhost:8848 # 注册中心地址 namespace: public group: SEATA_GROUP file: name: file.conf # 注册中心配置文件名称 path: /seata/config # 注册中心配置文件路径 ``` 3. 配置数据源 在application.yml文件中配置数据源,包括: ``` spring: datasource: url: jdbc:mysql://localhost:3306/seata?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver ``` 4. 配置Seata代理数据源 在Spring Boot启动类中配置Seata代理数据源: ``` @SpringBootApplication @EnableDiscoveryClient @MapperScan("com.example.demo.mapper") @EnableFeignClients(basePackages = "com.example.demo.feign") @EnableTransactionManagement public class SeataDemoApplication { public static void main(String[] args) { SpringApplication.run(SeataDemoApplication.class, args); } @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource() { return new DruidDataSource(); } @Bean public DataSourceProxy dataSourceProxy(DataSource dataSource) { return new DataSourceProxy(dataSource); } @Bean public GlobalTransactionScanner globalTransactionScanner() { return new GlobalTransactionScanner("seata-demo", "my_test_tx_group"); } } ``` 5. 编写业务代码 在业务代码中使用@GlobalTransactional注解标记需要参与分布式事务的方法,例如: ``` @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Autowired private OrderFeignClient orderFeignClient; @Override @GlobalTransactional public void createOrder(User user) { userMapper.insert(user); orderFeignClient.createOrder(user.getId()); } } ``` 以上就是在Spring Cloud Alibaba中使用Seata进行分布式事务的步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值