使用Seata实现分布式事务

一、安装与配置

  1、下载Seata

  点击进入下载页面(搜索Assets关键字,找到下载位置)

  2、修改配置文件

  D:\workset\javaset\seata-server-1.3.0\seata\conf\file.conf

1、将mode = "file" 改为 mode = "db"
2、修改db的配置信息 driverClassName = "com.mysql.cj.jdbc.Driver" url = "jdbc:mysql://localhost:3306/sltest?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai" user = "sl" password = "123456"

  D:\workset\javaset\seata-server-1.3.0\seata\conf\registry.conf

1、将registry的type = "file" 改为 type = "nacos"

2、修改registry的nacos的配置信息
   application = "seata-server"
   serverAddr = "127.0.0.1:8848"
   group = "SEATA_GROUP"
   namespace = ""
   cluster = "default"
   username = "nacos"
   password = "nacos"

3、将config的type = "file" 改为 type = "nacos"

4、修改config的nacos的配置信息
   serverAddr = "127.0.0.1:8848"
   namespace = ""
   group = "SEATA_GROUP"
   username = "nacos"
   password = "nacos"

  备注:Nacos的下载与安装点击这里

  3、创建数据库表

  点击这里可以下载,脚本如下

-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(96),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;
View Code

  双击启动 D:\workset\javaset\seata-server-1.3.0\seata\bin\seata-server.bat,Seata已经注册到Nacos里面了

  

   4、将配置注册到Nacos注册中心

   点击这里下载seata-1.3.0项目 下载后将整个script文件夹copy到Seata的根目录下

   源路径和copy后的路径分别为:

   原路径(seata-1.3.0源码中):C:\Users\shenl\Downloads\seata-1.3.0\script

   copy到的路径(seata-1.3.0的window安装路径):D:\workset\javaset\seata-server-1.3.0\seata\script

   修改文件 D:\workset\javaset\seata-server-1.3.0\seata\script\config-center\config.txt

1、将store.mode=file 改为 store.mode=db

2、修改db的配置信息
   store.db.datasource=druid
   store.db.dbType=mysql
   store.db.driverClassName=com.mysql.cj.jdbc.Driver
   store.db.url=jdbc:mysql://localhost:3306/sltest?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
   store.db.user=sl
   store.db.password=123456

  备注:文件中的配置项service.vgroupMapping.my_test_tx_group=default需要与项目application.yaml中的配置一致

  在git客户端执行脚本:sh nacos-config.sh,config.txt中的所有参数就配置到了Nacos中了

  nacos-config.sh在此目录中找(D:\workset\javaset\seata-server-1.3.0\seata\script\config-center\nacos)

  5、在所有用到分布式事务的数据库中添加表

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,
    PRIMARY KEY(`id`),
    UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

二、构建项目

  1、构建消费者项目

application.properties
# 应用名称
spring.application.name=service-consumer
# 应用服务 WEB 访问端口
server.port=7010
# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
# Nacos认证信息
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public


#配置seata的注册中心
seata.enabled=true
seata.application-id=${spring.application.name}
#配置事务分组
seata.tx-service-group=my_test_tx_group #与script\config-center\config.txt中配置一致
seata.registry.type=nacos
seata.registry.nacos.server-addr=127.0.0.1:8848
seata.registry.nacos.application=seata-server
seata.registry.nacos.namespace=
seata.registry.nacos.username=nacos
seata.registry.nacos.password=nacos
seata.registry.nacos.group=SEATA_GROUP
#配置seata的配置中心
seata.config.type=nacos
seata.config.nacos.server-addr=127.0.0.1:8848
seata.config.nacos.namespace=
seata.config.nacos.username=nacos
seata.config.nacos.password=nacos
seata.config.nacos.group=SEATA_GROUP

spring.datasource.url=jdbc:mysql://localhost:3306/sltest?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username=sl
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

mybatis.type-aliases-package=com.leiyuke.cloud.consumer.pojo

logging.level.root=info
pom.xml
<!-- nacos 服务注册发现(客户端)依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- nacos-config 配置中心依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

<!-- seata 分布式事务依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

<!-- openfeign 远程调用依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Application.java
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
IProductService.java
@FeignClient(name = "service-product",path = "stock")
public interface IProductService {

    @RequestMapping("/subStock")
    String subProduct();
}
ConsumerServiceImpl.java
... ...
@GlobalTransactional //分布式事务注解
public String addOrder() {
    Order order = orderMapper.getOrder();
    String value = order.getValue();
    Long num = Long.valueOf(value) + 1;
    String nextValue = String.format("%0"+6+"d",num);
    orderMapper.update(nextValue);//生成订单号,在数据库A

    //int a = 1/0;

    productService.subProduct();//库存减1,远程调用service-product微服务,在数据库B
    return "订单号为:"+nextValue;
}
... ...

  2、构建生产者项目

application.properties 只修改微服务名,端口,数据库配置,其余与消费者项目保持一致
pom.xml 与消费者项目保持一致
Application.java 启动类与消费者项目保持一致
GoodsServiceImpl.java
... ...
public void update() {
    //int a = 1/0;
    goodsMapper.update();
}
... ...

三、测试

  启动Nacos与Seata服务

  启动消费者与服务者两个项目

  1、给addOrder方法添加注解@GlobalTransactional

  分别去掉两处的注释(int a = 1/0)语句,使程序运行出错,两个数据中的值都没有改变,事务生效

  2、去掉addOrder方法的注解@GlobalTransactional

  分别去掉两处的注释(int a = 1/0)语句,使程序运行出错,发现订单库数据已修改,库存数据没有改变,事务不生效

 

  

posted @ 2022-07-10 12:37  雷雨客  阅读(226)  评论(0编辑  收藏  举报