Seata 分布式事务入门

Seata入门

环境准备
  • docker 安装 mysql

请移步https://blog.csdn.net/Zaric_001/article/details/113809164

  • 建立数据库seata

  • 导入表

/*
Navicat MySQL Data Transfer

Source Server         : 192.168.1.11
Source Server Version : 50733
Source Host           : 192.168.1.11:3306
Source Database       : seata

Target Server Type    : MYSQL
Target Server Version : 50733
File Encoding         : 65001

Date: 2021-02-14 21:13:05
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `branch_table`
-- ----------------------------
DROP TABLE IF EXISTS `branch_table`;
CREATE TABLE `branch_table` (
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(128) NOT NULL,
  `transaction_id` bigint(20) DEFAULT NULL,
  `resource_group_id` varchar(32) DEFAULT NULL,
  `resource_id` varchar(256) DEFAULT NULL,
  `branch_type` varchar(8) DEFAULT NULL,
  `status` tinyint(4) DEFAULT NULL,
  `client_id` varchar(64) DEFAULT NULL,
  `application_data` varchar(2000) DEFAULT NULL,
  `gmt_create` datetime(6) DEFAULT NULL,
  `gmt_modified` datetime(6) DEFAULT NULL,
  PRIMARY KEY (`branch_id`),
  KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of branch_table
-- ----------------------------

-- ----------------------------
-- Table structure for `global_table`
-- ----------------------------
DROP TABLE IF EXISTS `global_table`;
CREATE TABLE `global_table` (
  `xid` varchar(128) NOT NULL,
  `transaction_id` bigint(20) DEFAULT NULL,
  `status` tinyint(4) NOT NULL,
  `application_id` varchar(32) DEFAULT NULL,
  `transaction_service_group` varchar(32) DEFAULT NULL,
  `transaction_name` varchar(128) DEFAULT NULL,
  `timeout` int(11) DEFAULT NULL,
  `begin_time` bigint(20) DEFAULT NULL,
  `application_data` varchar(2000) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  `gmt_modified` datetime DEFAULT NULL,
  PRIMARY KEY (`xid`),
  KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),
  KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of global_table
-- ----------------------------

-- ----------------------------
-- Table structure for `lock_table`
-- ----------------------------
DROP TABLE IF EXISTS `lock_table`;
CREATE TABLE `lock_table` (
  `row_key` varchar(128) NOT NULL,
  `xid` varchar(96) DEFAULT NULL,
  `transaction_id` bigint(20) DEFAULT NULL,
  `branch_id` bigint(20) NOT NULL,
  `resource_id` varchar(256) DEFAULT NULL,
  `table_name` varchar(32) DEFAULT NULL,
  `pk` varchar(36) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  `gmt_modified` datetime DEFAULT NULL,
  PRIMARY KEY (`row_key`),
  KEY `idx_branch_id` (`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of lock_table
-- ----------------------------


  • 在微服务所在数据库创建表
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 DEFAULT CHARSET=utf8;

  • 准备seata配置文件

file.conf

注意: 此处是用mysql的容器进行数据库的操作的。在后面的执行中,seata-server容器会连接mysql容器,所以请把mysql容器名称定为mysql

url = “jdbc:mysql://mysql:3306/seata”

## transaction log store, only used in seata-server
store {
  ## store mode: file、db
  mode = "db"

  ## file store property
  file {
    ## store location dir
    dir = "sessionStore"
    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    maxBranchSessionSize = 16384
    # globe session size , if exceeded throws exceptions
    maxGlobalSessionSize = 512
    # file buffer size , if exceeded allocate new buffer
    fileWriteBufferCacheSize = 16384
    # when recover batch read size
    sessionReloadReadSize = 100
    # async, sync
    flushDiskMode = async
  }

  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "dbcp"
    ## mysql/oracle/h2/oceanbase etc.
    dbType = "mysql"
    driverClassName = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://mysql:3306/seata"
    user = "root"
    password = "123456"
    minConn = 1
    maxConn = 10
    globalTable = "global_table"
    branchTable = "branch_table"
    lockTable = "lock_table"
    queryLimit = 100
  }
}

registry.conf

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "file"

  nacos {
    serverAddr = "localhost"
    namespace = ""
    cluster = "default"
  }
  eureka {
    serviceUrl = "http://localhost:8761/eureka"
    application = "default"
    weight = "1"
  }
  redis {
    serverAddr = "localhost:6379"
    db = "0"
  }
  zk {
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
  }
  consul {
    cluster = "default"
    serverAddr = "127.0.0.1:8500"
  }
  etcd3 {
    cluster = "default"
    serverAddr = "http://localhost:2379"
  }
  sofa {
    serverAddr = "127.0.0.1:9603"
    application = "default"
    region = "DEFAULT_ZONE"
    datacenter = "DefaultDataCenter"
    cluster = "default"
    group = "SEATA_GROUP"
    addressWaitTime = "3000"
  }
  file {
    name = "file.conf"
  }
}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "file"

  nacos {
    serverAddr = "localhost"
    namespace = ""
    group = "SEATA_GROUP"
  }
  consul {
    serverAddr = "127.0.0.1:8500"
  }
  apollo {
    app.id = "seata-server"
    apollo.meta = "http://192.168.1.204:8801"
    namespace = "application"
  }
  zk {
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
  }
  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  file {
    name = "file.conf"
  }
}
  • docker 安装seata

    docker pull seataio/seata-server

  • 启动并挂载

此处挂载/root/docker-seata,下有两个文件夹,一个是config,下面有file.conf和registry.conf 还有一个是log用于存放日志。

docker run -d --name seata-server -p 8091:8091 --link mysql:mysql -e SEATA_CONFIG_NAME=file:/root/seata-config/registry -v /root/docker-seata/config:/root/seata-config -v //root/docker-seata/log:/root/logs -d seataio/seata-server

至此,环境准备就完毕了。

项目接入
  • pom

    <!-- 分布式事务 -->
    <dependency>
        <groupId>io.seata</groupId>
        <artifactId>seata-spring-boot-starter</artifactId>
        <version>1.1.0</version>
    </dependency>
    
  • application.properties
seata.enabled=true
#多个微服务 请保持id名称一致
seata.application-id=seate-server
# 分组名称
seata.tx-service-group=my_test_tx_group
seata.client.rm.async-commit-buffer-limit=1000
seata.client.rm.report-retry-count=5
seata.client.rm.table-meta-check-enable=false
seata.client.rm.report-success-enable=false
seata.client.rm.lock.retry-interval=10
seata.client.rm.lock.retry-times=30
seata.client.rm.lock.retry-policy-branch-rollback-on-conflict=true
seata.client.tm.commit-retry-count=5
seata.client.tm.rollback-retry-count=5
seata.client.undo.data-validation=true
seata.client.undo.log-serialization=jackson
seata.client.undo.log-table=undo_log
seata.client.log.exceptionRate=100
#my_test_tx_group 和配置的分组名称一直,且属性值default不要修改。
seata.service.vgroup-mapping.my_test_tx_group=default
#docker 中seata-server的访问地址
seata.service.grouplist.default=192.168.1.11:8091
seata.transport.shutdown.wait=3
seata.transport.thread-factory.boss-thread-prefix=NettyBoss
seata.transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker
seata.transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler
seata.transport.thread-factory.share-boss-worker=false
seata.transport.thread-factory.client-selector-thread-prefix=NettyClientSelector
seata.transport.thread-factory.client-selector-thread-size=1
seata.transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread
seata.transport.thread-factory.worker-thread-size=default
seata.transport.thread-factory.boss-thread-size=1
seata.transport.type=TCP
seata.transport.server=NIO
seata.transport.heartbeat=true
seata.transport.serialization=seata
seata.transport.compressor=none
seata.transport.enable-client-batch-send-request=true

备注的属性需要调整,其余看具体环境,一般不用调整。

  • 数据源代理配置

    import com.alibaba.druid.pool.DruidDataSource;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    
    import javax.sql.DataSource;
    
    @Configuration
    public class DatabaseConfiguration {
          
          
    
    
        /**
         * autowired datasource config
         */
        @Autowired
        private DataSourceProperties dataSourceProperties;
    
        /**
         * init durid datasource
         *
         * @Return: druidDataSource  datasource instance
         */
        @Bean
        @Primary
        public DruidDataSource druidDataSource(){
          
          
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setUrl(dataSourceProperties.getUrl());
            druidDataSource.setUsername(dataSourceProperties.getUsername());
            druidDataSource.setPassword(dataSourceProperties.getPassword());
            druidDataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
            druidDataSource.setInitialSize(0);
            druidDataSource.setMaxActive(180);
            druidDataSource.setMaxWait(60000);
            druidDataSource.setMinIdle(0);
            druidDataSource.setValidationQuery("Select 1 from DUAL");
            druidDataSource.setTestOnBorrow(false);
            druidDataSource.setTestOnReturn(false);
            druidDataSource.setTestWhileIdle(true);
            druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
            druidDataSource.setMinEvictableIdleTimeMillis(25200000);
            druidDataSource.setRemoveAbandoned(true);
            druidDataSource.setRemoveAbandonedTimeout(1800);
            druidDataSource.setLogAbandoned(true);
            return druidDataSource;
        }
        /**
         * init mybatis sqlSessionFactory
         * @Param: dataSourceProxy  datasource proxy
         * @Return: DataSourceProxy  datasource proxy
         */
        @Bean
        public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
          
          
            SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
            factoryBean.setDataSource(dataSource);
            factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                    .getResources("classpath*:/mapper/*.xml"));
            return factoryBean.getObject();
        }
    
    
    }
    
  • 调用示例

    @GlobalTransactional(timeoutMills = 300000, name = "base2020-seata-example") //name可以修改
    @Override
    public void update(Double acccount) {
          
          
        Bank1 bank1 = bank1Dao.selectByPrimaryKey(2l);
        bank1.setAccountBalance(bank1.getAccountBalance()-acccount);
        bank1Dao.updateByPrimaryKeySelective(bank1);
    
        String modify = bank2Feign.modify(acccount+"");
        if(modify.equals("error")){
          
          
            throw new RuntimeException("分支处理失败");//看是否成功
        }else{
          
          
            System.out.println("ok");
        }
    }
    
  • 查看数据库的操作结果。

  • 日志

    成功

2021-02-14 12:43:47.036  INFO --- [    NettyServerNIOWorker_1_1_4] i.s.c.r.processor.server.RegTmProcessor  : TM register success,message:RegisterTMRequest{applicationId='seate-server', transactionServiceGroup='my_test_tx_group'},channel:[id: 0x3a404bfd, L:/172.17.0.4:8091 - R:/192.168.1.4:58903],client version:1.1.0
2021-02-14 12:43:47.043  INFO --- [          batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler         : SeataMergeMessage timeout=300000,transactionName=base2020-seata-example
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:43:47.043  INFO --- [  ServerHandlerThread_1_45_500] i.s.s.coordinator.DefaultCoordinator     : Begin new global transaction applicationId: seate-server,transactionServiceGroup: my_test_tx_group, transactionName: base2020-seata-example,timeout:300000,xid:172.17.0.4:8091:36130662144475151
2021-02-14 12:43:47.155  INFO --- [  ServerHandlerThread_1_46_500] i.s.c.r.processor.server.RegRmProcessor  : RM register success,message:RegisterRMRequest{resourceIds='jdbc:mysql://192.168.1.11:3306/bank1', applicationId='seate-server', transactionServiceGroup='my_test_tx_group'},channel:[id: 0x76bfd1a0, L:/172.17.0.4:8091 - R:/192.168.1.4:58904],client version:1.1.0
2021-02-14 12:43:47.169  INFO --- [          batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler         : SeataMergeMessage xid=172.17.0.4:8091:36130662144475151,branchType=AT,resourceId=jdbc:mysql://192.168.1.11:3306/bank1,lockKey=account_info:2
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:43:47.169  INFO --- [  ServerHandlerThread_1_47_500] i.seata.server.coordinator.AbstractCore  : Register branch successfully, xid = 172.17.0.4:8091:36130662144475151, branchId = 36130662144475152, resourceId = jdbc:mysql://192.168.1.11:3306/bank1 ,lockKeys = account_info:2
2021-02-14 12:43:47.755  INFO --- [          batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler         : SeataMergeMessage xid=172.17.0.4:8091:36130662144475151,extraData=null
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:43:48.619  INFO --- [           AsyncCommitting_1_1] io.seata.server.coordinator.DefaultCore  : Committing global transaction is successfully done, xid = 172.17.0.4:8091:36130662144475151.
2021-02-14 12:44:05.814  INFO --- [          batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler         : SeataMergeMessage timeout=300000,transactionName=base2020-seata-example
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:44:05.814  INFO --- [  ServerHandlerThread_1_50_500] i.s.s.coordinator.DefaultCoordinator     : Begin new global transaction applicationId: seate-server,transactionServiceGroup: my_test_tx_group, transactionName: base2020-seata-example,timeout:300000,xid:172.17.0.4:8091:36130662144475153
2021-02-14 12:44:05.916  INFO --- [          batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler         : SeataMergeMessage xid=172.17.0.4:8091:36130662144475153,branchType=AT,resourceId=jdbc:mysql://192.168.1.11:3306/bank1,lockKey=account_info:2
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:44:05.916  INFO --- [   ServerHandlerThread_1_1_500] i.seata.server.coordinator.AbstractCore  : Register branch successfully, xid = 172.17.0.4:8091:36130662144475153, branchId = 36130662144475154, resourceId = jdbc:mysql://192.168.1.11:3306/bank1 ,lockKeys = account_info:2
2021-02-14 12:44:06.089  INFO --- [          batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler         : SeataMergeMessage xid=172.17.0.4:8091:36130662144475153,extraData=null
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:44:06.618  INFO --- [           AsyncCommitting_1_1] io.seata.server.coordinator.DefaultCore  : Committing global transaction is successfully done, xid = 172.17.0.4:8091:36130662144475153.

失败

2021-02-14 12:41:55.581  INFO --- [  ServerHandlerThread_1_41_500] i.s.s.coordinator.DefaultCoordinator     : Begin new global transaction applicationId: seate-server,transactionServiceGroup: my_test_tx_group, transactionName: base2020-seata-example,timeout:300000,xid:172.17.0.4:8091:36130662144475149
2021-02-14 12:41:55.581  INFO --- [          batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler         : SeataMergeMessage timeout=300000,transactionName=base2020-seata-example
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:41:56.323  INFO --- [          batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler         : SeataMergeMessage xid=172.17.0.4:8091:36130662144475149,branchType=AT,resourceId=jdbc:mysql://192.168.1.11:3306/bank1,lockKey=account_info:2
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:41:56.323  INFO --- [  ServerHandlerThread_1_42_500] i.seata.server.coordinator.AbstractCore  : Register branch successfully, xid = 172.17.0.4:8091:36130662144475149, branchId = 36130662144475150, resourceId = jdbc:mysql://192.168.1.11:3306/bank1 ,lockKeys = account_info:2
2021-02-14 12:41:58.114  INFO --- [          batchLoggerPrint_1_1] i.s.c.r.p.server.BatchLogHandler         : SeataMergeMessage xid=172.17.0.4:8091:36130662144475149,extraData=null
,clientIp:192.168.1.4,vgroup:my_test_tx_group
2021-02-14 12:41:58.202  INFO --- [  ServerHandlerThread_1_43_500] io.seata.server.coordinator.DefaultCore  : Rollback branch transaction successfully, xid = 172.17.0.4:8091:36130662144475149 branchId = 36130662144475150
2021-02-14 12:41:58.203  INFO --- [  ServerHandlerThread_1_43_500] io.seata.server.coordinator.DefaultCore  : Rollback global transaction successfully, xid = 172.17.0.4:8091:36130662144475149.

猜你喜欢

转载自blog.csdn.net/Zaric_001/article/details/113811135