开发者社区> code-x> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Seata分布式事务环境搭建

简介: Seata分布式事务环境搭建
+关注继续查看

下载seata服务端

https://github.com/seata/seata/releases

修改registry.conf

这里使用nacos做注册中心和配置中心, 也就不需要服务端的file.conf了

但是使用nacos时, nacos的密码不能有特殊符号, 否则seata可能连接不上(1.5.0已修复)

registry {
  type = "nacos"
  nacos {
    application = "seata-server"
    serverAddr = "127.0.0.1:8848"
    group = "SEATA_GROUP"
    namespace = "e794b575-4231-4935-8271-145c5840d392"
    cluster = "default"
    username = "nacos"
    password = "nacos"
  }
}
config {
  type = "nacos"
  nacos {
    serverAddr = "127.0.0.1:8848"
    namespace = "e794b575-4231-4935-8271-145c5840d392"
    group = "SEATA_GROUP"
    username = "nacos"
    password = "nacos"
    dataId = "seataServer.properties"
  }
}


seata服务端需要的几个表: https://github.com/seata/seata/blob/develop/script/server/db/mysql.sql

其他的一些相关的脚本https://github.com/seata/seata/tree/develop/script

nacos建立命名空间

新增配置文件

Data ID: seataServer.properties

Group: SEATA_GROUP

seataServer.properties配置内容

### seata
store.mode=db
store.publicKey=
## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.
store.db.datasource=druid
## mysql/oracle/postgresql/h2/oceanbase etc.
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param
store.db.url=jdbc:mysql://192.168.101.128:3309/seata?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&&serverTimezone=Asia/Shanghai
store.db.user=root
store.db.password=123456
store.db.minConn=5
store.db.maxConn=100
store.db.globalTable = global_table
store.db.branchTable = branch_table
store.db.lockTable =lock_table
store.db.queryLimit = 100
store.db.maxWait = 5000
## transport
# tcp udt unix-domain-socket
transport.type=TCP
#NIO NATIVE
transport.server=NIO
#enable heartbeat
transport.heartbeat=true
transport.serialization=seata
transport.compressor=none
transport.threadFactory.bossThreadPrefix = NettyBoss
transport.threadFactory.workerThreadPrefix = NettyServerNIOWorker
transport.threadFactory.serverExecutorThread-prefix = NettyServerBizHandler
transport.threadFactory.shareBossWorker = false
transport.threadFactory.clientSelectorThreadPrefix = NettyClientSelector
transport.threadFactory.clientSelectorThreadSize = 1
transport.threadFactory.clientWorkerThreadPrefix = NettyClientWorkerThread
transport.threadFactory.bossThreadSize = 1
transport.threadFactory.workerThreadSize = default
# 销毁服务器时, 等待几秒钟
transport.shutdown.wait=3
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000


单体服务多库事务

SpringBoot项目引入依赖

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.4.2</version>
</dependency>


项目配置文件

seata:
  application-id: test #这里填你应用的id
  service:
    grouplist:
      # seata-server地址
      default: 127.0.0.1:8091
    # 分组事务
    vgroup-mapping:
      global_tx_group: default
      enable-degrade: false
      disable-global-transaction: false
  # 是否开启spring-boot自动装配
  enabled: true
  # 是否启用数据源 bean 的自动代理
  enable-auto-data-source-proxy: true
  tx-service-group: global_tx_group
  client:
    tm:
      # 一阶段全局提交结果上报TC重试次数 默认1次,建议大于1
      commit-retry-count: 3
      # 一阶段全局回滚结果上报TC重试次数 默认1次,建议大于1
      rollback-retry-count: 3
    rm:
      # 是否上报一阶段成功 true、false,从1.1.0版本开始,默认false.true用于保持分支事务生命周期记录完整,false可提高不少性能
      report-success-enable: true
      # 自动刷新缓存中的表结构 默认false
      table-meta-check-enable: true
      # 一阶段结果上报TC重试次数
      report-retry-count: 5
      # 异步提交缓存队列长度 默认10000。 二阶段提交成功,RM异步清理undo队列
      async-commit-buffer-limit: 1000
      lock:
        # 校验或占用全局锁重试间隔 默认10,单位毫秒
        retry-interval: 10
        # 分支事务与其它全局回滚事务冲突时锁策略 默认true,优先释放本地锁让回滚成功
        retry-policy-branch-rollback-on-conflict: true
        # 校验或占用全局锁重试次数
        retry-times: 30
    undo:
      # 自定义undo表名 默认undo_log
      log-table: seata_undo_log
      # 二阶段回滚镜像校验
      data-validation: true
      # undo log序列化方式
      log-serialization: jackson
  transport:
    type: TCP
    server: NIO
    heartbeat: true
    # client和server通信编解码方式 seata(ByteBuf)、protobuf、kryo、hession、fst,默认seata
    serialization: seata
    # client和server通信数据压缩方式 none、gzip,默认none
    compressor: none
    thread-factory:
      boss-thread-prefix: NettyBoss
      client-worker-thread-prefix: NettyServerNIOWorker
      server-executor-thread-prefix: NettyServerBizHandler
      client-selector-thread-size: 1
      client-selector-thread-prefix: NettyClientWorkerThread


简单使用, 配合dynamic-datasource-spring-boot-starter使用

@Autowired
StaffMapper staffMapper;
    
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public void globalTx() {
    userService.updateMaster();
    userService.updateIndependent();
    //模拟异常回滚
    int i = 1 / 0;
}
@DS("master")
@Transactional(rollbackFor = Exception.class)
public void updateMaster() {
    User user1 = baseDao.selectById(1);
    user1.setAge(999);
    baseDao.updateById(user1);
    User user2 = baseDao.selectById(2);
    user2.setAge(999);
    baseDao.updateById(user2);
}
@DS("independent")
@Transactional(rollbackFor = Exception.class)
public void updateIndependent() {
    Staff staff1 = staffMapper.selectById(1);
    staff1.setAge(999);
    staffMapper.updateById(staff1);
    Staff staff2 = staffMapper.selectById(2);
    staff2.setAge(999);
    staffMapper.updateById(staff2);
}


可以观察到seata_undo_log中的undo记录

SELECT CAST(rollback_info AS char) FROM seata_undo_log


{
    "@class": "io.seata.rm.datasource.undo.BranchUndoLog",
    "xid": "192.168.101.1:8091:6593516322371825665",
    "branchId": 6593516322371825668,
    "sqlUndoLogs": [
        "java.util.ArrayList",
        [
            {
                "@class": "io.seata.rm.datasource.undo.SQLUndoLog",
                "sqlType": "UPDATE",
                "tableName": "staff",
                "beforeImage": {
                    "@class": "io.seata.rm.datasource.sql.struct.TableRecords",
                    "tableName": "staff",
                    "rows": [
                        "java.util.ArrayList",
                        [
                            {
                                "@class": "io.seata.rm.datasource.sql.struct.Row",
                                "fields": [
                                    "java.util.ArrayList",
                                    [
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "id",
                                            "keyType": "PRIMARY_KEY",
                                            "type": 4,
                                            "value": [
                                                "java.lang.Long",
                                                1
                                            ]
                                        },
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "name",
                                            "keyType": "NULL",
                                            "type": 12,
                                            "value": "1"
                                        },
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "age",
                                            "keyType": "NULL",
                                            "type": 4,
                                            "value": 2
                                        }
                                    ]
                                ]
                            }
                        ]
                    ]
                },
                "afterImage": {
                    "@class": "io.seata.rm.datasource.sql.struct.TableRecords",
                    "tableName": "staff",
                    "rows": [
                        "java.util.ArrayList",
                        [
                            {
                                "@class": "io.seata.rm.datasource.sql.struct.Row",
                                "fields": [
                                    "java.util.ArrayList",
                                    [
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "id",
                                            "keyType": "PRIMARY_KEY",
                                            "type": 4,
                                            "value": [
                                                "java.lang.Long",
                                                1
                                            ]
                                        },
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "name",
                                            "keyType": "NULL",
                                            "type": 12,
                                            "value": "1"
                                        },
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "age",
                                            "keyType": "NULL",
                                            "type": 4,
                                            "value": 999
                                        }
                                    ]
                                ]
                            }
                        ]
                    ]
                }
            },
            {
                "@class": "io.seata.rm.datasource.undo.SQLUndoLog",
                "sqlType": "UPDATE",
                "tableName": "staff",
                "beforeImage": {
                    "@class": "io.seata.rm.datasource.sql.struct.TableRecords",
                    "tableName": "staff",
                    "rows": [
                        "java.util.ArrayList",
                        [
                            {
                                "@class": "io.seata.rm.datasource.sql.struct.Row",
                                "fields": [
                                    "java.util.ArrayList",
                                    [
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "id",
                                            "keyType": "PRIMARY_KEY",
                                            "type": 4,
                                            "value": [
                                                "java.lang.Long",
                                                2
                                            ]
                                        },
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "name",
                                            "keyType": "NULL",
                                            "type": 12,
                                            "value": "2"
                                        },
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "age",
                                            "keyType": "NULL",
                                            "type": 4,
                                            "value": 3
                                        }
                                    ]
                                ]
                            }
                        ]
                    ]
                },
                "afterImage": {
                    "@class": "io.seata.rm.datasource.sql.struct.TableRecords",
                    "tableName": "staff",
                    "rows": [
                        "java.util.ArrayList",
                        [
                            {
                                "@class": "io.seata.rm.datasource.sql.struct.Row",
                                "fields": [
                                    "java.util.ArrayList",
                                    [
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "id",
                                            "keyType": "PRIMARY_KEY",
                                            "type": 4,
                                            "value": [
                                                "java.lang.Long",
                                                2
                                            ]
                                        },
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "name",
                                            "keyType": "NULL",
                                            "type": 12,
                                            "value": "2"
                                        },
                                        {
                                            "@class": "io.seata.rm.datasource.sql.struct.Field",
                                            "name": "age",
                                            "keyType": "NULL",
                                            "type": 4,
                                            "value": 999
                                        }
                                    ]
                                ]
                            }
                        ]
                    ]
                }
            }
        ]
    ]
}


可以看到该表内存储了数据操作前和操作后的记录

微服务项目分布式事务

如果是微服务项目, 需要分布式事务支持, 配置如下

引入依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>


配置和单体服务多库事务是一样的, seata.application-id可以不填, 默认取当前应用id

每个模块都需要配置, 因为seata需要代理数据源

但实际1.4.2版本使用jackson/fastjson序列化Date字段时会失败(https://github.com/seata/seata/issues/3883), 可以替换序列化方式为kryo

需要额外引入依赖

<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-serializer-kryo</artifactId>
    <version>1.4.2</version>
</dependency>


简易demo

@Autowired
RoleFeignClient roleFeignClient;
@Autowired
StaffFeignClient staffFeignClient;
    
@GlobalTransactional(rollbackFor = Exception.class)
public RestResult<Boolean> globalTxTest() {
    log.info("xid: {}", RootContext.getXID());
    roleFeignClient.updateRole();
    staffFeignClient.updateUser();
    int i = 1 / 0;
    return RestResult.ok();
}


@Override
@Transactional(rollbackFor = Exception.class)
public RestResult<Boolean> updateRole() {
    log.info("xid: {}", RootContext.getXID());
    RolePO role1 = roleDAO.selectById(1);
    role1.setName("1111111111");
    roleDAO.updateById(role1);
    RolePO role2 = roleDAO.selectById(2);
    role2.setName("2222222");
    roleDAO.updateById(role2);
    return RestResult.ok();
}


@Override
@Transactional(rollbackFor = Exception.class)
public RestResult<Boolean> updateUser() {
    log.info("xid: {}", RootContext.getXID());
    StaffPO staff1 = baseMapper.selectById(1);
    staff1.setAge(999);
    baseMapper.updateById(staff1);
    StaffPO staff2 = baseMapper.selectById(2);
    staff2.setAge(999);
    baseMapper.updateById(staff2);
    return RestResult.ok();
}


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
SpringCloud微服务实战——搭建企业级开发框架(二十七):集成多数据源+Seata分布式事务+读写分离+分库分表
读写分离:为了确保数据库产品的稳定性,很多数据库拥有双机热备功能。也就是,第一台数据库服务器,是对外提供增删改业务的生产服务器;第二台数据库服务器,主要进行读的操作。   目前有多种方式实现读写分离,一种是Mycat这种数据库中间件,需要单独部署服务,通过配置来实现读写分离,不侵入到业务代码中;还有一种是dynamic-datasource/shardingsphere-jdbc这种,需要在业务代码引入jar包进行开发。
130 0
springcloud整合seata实现分布式事务
springcloud整合seata实现分布式事务
99 0
微服务架构 | 11.1 整合 Seata AT 模式实现分布式事务
Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务;它提供了 AT、TCC、Saga 和 XA 事务模式,为开发者提供了一站式的分布式事务解决方案;
107 0
分布式事务中间件 Seata学习系列之一:初识Seata
本文主要介绍了分布式事务的概念以及当前分布式事务存在的不足之处,同时着重介绍了Seata分布式事务处理机制以及的优势之处。
70 0
HDFS伪分布式环境搭建(中)
HDFS伪分布式环境搭建
55 0
Seata 分支事务
前面,我们已经介绍了 Seata 的整体设计思想,接下来我们深入到其实现细节中,本文先来介绍 Seata 中分支事务的整体实现思想。
71 0
分布式事务
分布式事务
59 0
Hadoop全分布式环境搭建
<p><span style="font-size:14px"><span style="color:#ff0000">视频演示:<a target="_blank" href="http://v.youku.com/v_show/id_XNTY4NDM3NDQ4.html">http://v.youku.com/v_show/id_XNTY4NDM3NDQ4.html</a></span
1364 0
阿里分布式服务框架Dubbo的架构总结
Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。
1989 0
+关注
14
文章
1
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载