Seata AT分布式事务简单集成

Seata 是什么?

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
关于Seata的介绍和事务的详细流转细节参考 Seata官网

本文采用docker部署seata服务
1、运行镜像

docker run --name seata-server -p 8091:8091 -d seataio/seata-server

2、复制配置文件到主机 当前目录

docker cp seata-server:/seata-server .

3、停止服务

docker stop seata-server

4、删除服务

docker rm seata-server

5、重新运行服务
# 脚本
# BEGIN ANSIBLE MANAGED BLOCK
#!/bin/bash
HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
docker rm -f seata-server;
docker run --name seata-server \
  --restart=always \
  -v $HOME/seata-server:/seata-server \
  -e SEATA_IP=192.168.8.43 \
  -e SEATA_PORT=8091 \
  -p 8091:8091 \
  -d seataio/seata-server
# END ANSIBLE MANAGED BLOCK
6、切换到seata配置文件目录

cd /seata-server/resources
修改register.conf

  • 如果是配置中心是file的话,会使用file.conf里面的配置,如果是其他,使用配置中心的配置
  • 直连 eureka/consul/apollo/etcd/zookeeper/sofa/redis/file
本文采用nacos配置
  • 修改 register.type 和 config.type 为 nacos
    然后修改nacos的相关配置
# 注册中心配置
registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos" # 注册类型
  loadBalance = "RandomLoadBalance"
  loadBalanceVirtualNodes = 10

  nacos {
    application = "seata-server-lss"
    serverAddr = "123.57.26.81:8848"
    group = "SEATA_GROUP"
    namespace = "lss_test"
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
}
# 配置中心配置
config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "nacos"

  nacos {
    serverAddr = "123.57.26.81:8848"
    namespace = "lss_test"
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
    dataId = "seataServer.properties"
  }
}
7、重启seata-server

docker restart seata-server
查看nacos,发现seata 服务端已正常启动

image.png

接下来配置项目

参考seata官网的账户、订单项目

1、新建项目,如下图
image.png
2、pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
<!--        <relativePath />-->
<!--        <groupId>org.lss</groupId>-->
<!--        <artifactId>project</artifactId>-->
<!--        <version>1.0.0</version>-->
    </parent>


    <groupId>com.lss</groupId>
    <artifactId>seata_xa</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>

    <properties>
        <seata.version>1.4.0</seata.version>
        <alibaba.cloud.version>2.2.3.RELEASE</alibaba.cloud.version>
    </properties>

    <modules>
        <module>business_xa</module>
        <module>order_xa</module>
        <module>account_xa</module>
    </modules>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--  lombok依赖 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
        <!-- durid -->
<!--        <dependency>-->
<!--            <groupId>com.alibaba</groupId>-->
<!--            <artifactId>druid-spring-boot-starter</artifactId>-->
<!--            <version>1.1.10</version>-->
<!--        </dependency>-->
        <!--nacos动态加载配置-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--nacos服务注册发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!-- seata 引入此依赖才能成功-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
        <!--   由于版本问题,需要排除以下依赖  -->
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>com.alibaba.cloud</groupId>-->
<!--            <artifactId>spring-cloud-alibaba-seata</artifactId>-->
<!--            <version>2.0.0.RELEASE</version>-->
<!--            <exclusions>-->
<!--                <exclusion>-->
<!--                    <groupId>io.seata</groupId>-->
<!--                    <artifactId>seata-all</artifactId>-->
<!--                </exclusion>-->
<!--            </exclusions>-->
<!--        </dependency>-->
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>${seata.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!-- feign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>

        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
<!--            <scope>runtime</scope>-->
        </dependency>
        <!-- jdbc -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR8</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${alibaba.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>
3、config.txt 和 nacos-config.sh是从 官网 拷出来的配置,需要上传到nacos,具体也可参考/seata-server/resources/README-zh.md 里面的描述
  • nacos-init.sh 是运行 nacos-config.sh 的脚本

#-h: host, the default value is localhost.
#
#-p: port, the default value is 8848.
#
#-g: Configure grouping, the default value is 'SEATA_GROUP'.
#
#-t: Tenant information, corresponding to the namespace ID field of Nacos, the default value is ''.
#
#-u: username, nacos 1.2.0+ on permission control, the default value is ''.
#
#-w: password, nacos 1.2.0+ on permission control, the default value is ''.

bash nacos-config.sh -h 123.57.26.81 -p 8848 -g SEATA_GROUP -t lss_test -u nacos -w nacos

执行后 bash nacos-init.sh 后,在nacos上可查看到相关配置

image.png

项目整体结构图

image.png
4、business_xa项目
  • bootstrap.yml
server:
  port: 17000

nacos:
  namespace: lss_test
  address: 123.57.26.81:8848

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/xa_order?useSSL=false&serverTimezone=UTC
    username: root
    password: 12345678
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: business_xa
  cloud:
    nacos:
      namespace: ${nacos.namespace}
      server-addr: ${nacos.address}
      config:
        enabled: true
        namespace: ${spring.cloud.nacos.namespace}
#          file-extension: yml
#          shared-configs:
#            - data-id: common.yml
#              refresh: true
      discovery:
        enabled: true
        namespace: ${spring.cloud.nacos.namespace}
        register-enabled: true

# seata 配置
seata:
  # 注册信息
  registry:
    type: nacos
    nacos:
      application: seata-server-lss   # 这个是 seata 服务端的应用名称
      server-addr: ${nacos.address}  # nacos 服务地址
      group : "SEATA_GROUP"           # nacos 分组
      namespace: ${nacos.namespace}           # nacos 命名空间
      username: "nacos"
      password: "nacos"
  # 配置信息
  config:
    type: nacos
    nacos:
      server-addr: 123.57.26.81:8848
      group: "SEATA_GROUP"
      namespace: ${nacos.namespace}
      username: "nacos"
      password: "nacos"
  application-id: ${spring.application.name}
  tx-service-group: seata-server_xa_test    # 自定义事物组 tc
  • BusinessController.java
package com.lss.sample.operator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("api")
@RestController
@Slf4j
public class BusinessController {


    @Autowired
    BusinessService businessService;

    @GetMapping("purchase")
    public String purchase(@RequestParam(value = "type", defaultValue = "1") Integer type ) {

        try {
            businessService.purchase(type);
        } catch (Exception exx) {
            log.info("异常:{}", exx);
            return "Purchase Failed:" + exx.getMessage();
        }
        return "SUCCESS";
    }
}
  • BusinessService.java
package com.lss.sample.operator;

import com.lss.sample.feign.AccountFeignClient;
import com.lss.sample.feign.OrderFeignClient;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class BusinessService {

    final String SUCCESS = "SUCCESS";

    @Autowired
    private OrderFeignClient orderFeignClient;

    @Autowired
    AccountFeignClient accountFeignClient;

    @GlobalTransactional(rollbackFor = Exception.class)
    public void purchase(Integer type) {
        String xid = RootContext.getXID();
        log.info("business-xid:{}", xid);


        String accountResult = accountFeignClient.add();
        throw new RuntimeException("账户服务调用失败,事务回滚!");

        if (!SUCCESS.equals(accountResult)) {
            throw new RuntimeException("账户服务调用失败,事务回滚!");
        }else {
            log.info("账户服务调用成功...");
        }
//
        String orderResult = orderFeignClient.create(type);

        if (!SUCCESS.equals(orderResult)) {
            log.info("订单服务调用失败...");
            throw new RuntimeException("订单服务调用失败,事务回滚!");
        }else {
            log.info("订单服务调用成功...");
        }
    }
}
  • AccountFeignClient.java
package com.lss.sample.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(name = "AccountFeignClient", url = "127.0.0.1:17002")
public interface AccountFeignClient {

    @GetMapping("api/add")
    String add();
}

  • OrderFeignClient.java
package com.lss.sample.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "OrderFeignClient", url = "127.0.0.1:17001")
public interface OrderFeignClient {

    @GetMapping("api/create")
    String create(@RequestParam(value = "type") Integer type);

}
  • 启动类 BusinessXAApplication.java
package com.lss.sample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class BusinessXAApplication {
    public static void main(String[] args) {
        SpringApplication.run(BusinessXAApplication.class, args);
    }
}

5、account_xa项目
  • account_xa服务的bootstrap.yml
server:
  port: 17002

nacos:
  namespace: lss_test
  address: 123.57.26.81:8848

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/xa_account?useSSL=false&serverTimezone=UTC
    username: root
    password: 12345678
#    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: account_xa
  cloud:
    nacos:
      namespace: ${nacos.namespace}
      server-addr: ${nacos.address}
      config:
        enabled: true
        namespace: ${spring.cloud.nacos.namespace}
#          file-extension: yml
#          shared-configs:
#            - data-id: common.yml
#              refresh: true
      discovery:
        enabled: true
        namespace: ${spring.cloud.nacos.namespace}
        register-enabled: true

# seata 配置
seata:
  # 注册信息
  registry:
    type: nacos
    nacos:
      application: seata-server-lss   # 这个是 seata 服务端的应用名称
      server-addr: ${nacos.address}  # nacos 服务地址
      group : "SEATA_GROUP"           # nacos 分组
      namespace: ${nacos.namespace}           # nacos 命名空间
      username: "nacos"
      password: "nacos"
  # 配置信息
  config:
    type: nacos
    nacos:
      server-addr: 123.57.26.81:8848
      group: "SEATA_GROUP"
      namespace: ${nacos.namespace}
      username: "nacos"
      password: "nacos"
  application-id: ${spring.application.name}
  tx-service-group: seata-server_xa_test    # 自定义事物组 tc
  • AccountController.java
package com.lss.sample.operator;

import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("api")
@Slf4j
public class AccountController {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @GetMapping("add")
    public String add() {
        String xid = RootContext.getXID();
        log.info("account-xid:{}", xid);
        jdbcTemplate.update("update account set account = 10000 where id = 4 ");
        return "SUCCESS";
    }
}

  • DataSourceConfig.java
package com.lss.sample.config;

import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import io.seata.rm.datasource.xa.DataSourceProxyXA;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DruidDataSource druidDataSource() {
        return new DruidDataSource();
    }

    @Bean("dataSourceProxy")
    public DataSource dataSource(DruidDataSource druidDataSource) {
        // DataSourceProxy for AT mode
//         return new DataSourceProxy(druidDataSource);

        // DataSourceProxyXA for XA mode
        return new DataSourceProxyXA(druidDataSource);
    }

    @Bean("jdbcTemplate")
    public JdbcTemplate jdbcTemplate(DataSource dataSourceProxy) {
        return new JdbcTemplate(dataSourceProxy);
    }
}
  • 启动类 AccountXAApplication
package com.lss.sample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableFeignClients
@EnableTransactionManagement
public class AccountXAApplication {
    public static void main(String[] args) {
        SpringApplication.run(AccountXAApplication.class, args);
    }
}
6、order_xa项目
  • bootstrap.yml
server:
  port: 17001

nacos:
  namespace: lss_test
  address: 123.57.26.81:8848

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/xa_order?useSSL=false&serverTimezone=UTC
    username: root
    password: 12345678
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: order_xa
  cloud:
    nacos:
      namespace: ${nacos.namespace}
      server-addr: ${nacos.address}
      config:
        enabled: true
        namespace: ${spring.cloud.nacos.namespace}
#          file-extension: yml
#          shared-configs:
#            - data-id: common.yml
#              refresh: true
      discovery:
        enabled: true
        namespace: ${spring.cloud.nacos.namespace}
        register-enabled: true

# seata 配置
seata:
  # 注册信息
  registry:
    type: nacos
    nacos:
      application: seata-server-lss   # 这个是 seata 服务端的应用名称
      server-addr: ${nacos.address}  # nacos 服务地址
      group : "SEATA_GROUP"           # nacos 分组
      namespace: ${nacos.namespace}           # nacos 命名空间
      username: "nacos"
      password: "nacos"
  # 配置信息
  config:
    type: nacos
    nacos:
      server-addr: 123.57.26.81:8848
      group: "SEATA_GROUP"
      namespace: ${nacos.namespace}
      username: "nacos"
      password: "nacos"
  application-id: ${spring.application.name}
  tx-service-group: seata-server_xa_test    # 自定义事物组 tc
  • OrderController.java
package com.lss.sample.operator;

import io.seata.core.context.RootContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("api")
@RestController
@Slf4j
public class OrderController {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @GetMapping("create")
    public String create(@RequestParam(value = "type") Integer type) {

        String xid = RootContext.getXID();
        log.info("account-xid:{}", xid);
        try {
            deal(type);
        } catch (Exception e) {
            return "FAIL";
        }
        return "SUCCESS";
    }
    @Transactional
    public void deal(Integer type) {
        jdbcTemplate.update("update `order` set num = 100 where id = 1 ");
        if (type.equals(2)) {
            log.info("order 调用异常...");
            throw new RuntimeException("order 调用异常...");
        }

    }
}
  • DataSourceConfig
package com.lss.sample.config;

import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.xa.DataSourceProxyXA;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DruidDataSource druidDataSource() {
        return new DruidDataSource();
    }

    @Bean("dataSourceProxy")
    public DataSource dataSource(DruidDataSource druidDataSource) {
        // DataSourceProxy for AT mode
//         return new DataSourceProxy(druidDataSource);

        // DataSourceProxyXA for XA mode
        return new DataSourceProxyXA(druidDataSource);
    }

    @Bean("jdbcTemplate")
    public JdbcTemplate jdbcTemplate(DataSource dataSourceProxy) {
        return new JdbcTemplate(dataSourceProxy);
    }
}
  • 启动类OrderXAApplication.java
package com.lss.sample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class OrderXAApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderXAApplication.class, args);
    }
}

运行项目

1、business_xa、account_xa、order_xa依次运行后,在nacos上发现项目都已经注册上去了,但是项目会报一个错误

no available service 'null' found, please make sure registry config correct

报错原因在这个类里 io.seata.core.rpc.netty.NettyClientChannelManager
根据seata导入客户端相关配置后
添加一个配置

  • service.vgroupMapping.(自定义的事务组名称 tc)=default 就可以了
    本文的配置为: service.vgroupMapping.seata-server_xa_test = default
    nacos上如下图
    image.png
2、在数据库中添加sql脚本
  • xa_account 库
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `account` varchar(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;


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=12 DEFAULT CHARSET=utf8;
  • xa_order 库
DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `num` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

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=12 DEFAULT CHARSET=utf8;
3、至此,seata集成已经完成了,启动项目后,访问business_xa服务

curl http://localhost:17000/api/purchase?type=1
发现数据库数据被正常更新
重新手动更新数据后,再次访问
curl http://localhost:17000/api/purchase?type=2
发现数据库数据回滚

集成过程可能还会有其他的问题,本文已经尽可能写到了,希望对你学习seata有所帮助
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容