zoukankan      html  css  js  c++  java
  • ShardingJdbc-分表;分库;分库分表;读写分离;一主多从+分表;一主多从+分库分表;公共表;数据脱敏;分布式事务

    创建项目

    一顿下一步,勾选web、lombok等插件

    分表

    导包

    ShardingJdbc

    官方最新稳定版4.1.1

    <!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/sharding-jdbc-spring-boot-starter -->
    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
        <version>4.1.1</version>
    </dependency>
    

    Mysql

    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.25</version>
    </dependency>
    

    Druid

    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.6</version>
    </dependency>
    

    MyBatisPlus

    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.4.3</version>
    </dependency>
    

    表结构

    注意:之前我这表名叫table_0,结果一直报找不到表,后来发现,不能用关键字

    CREATE TABLE `master_db`.`my_table_0` (
      `id` BIGINT (20) NOT NULL,
      `source` VARCHAR (20),
      `remark` VARCHAR (100),
      PRIMARY KEY (`id`)
    );
    
    CREATE TABLE `master_db`.`my_table_1` (
      `id` BIGINT (20) NOT NULL,
      `source` VARCHAR (20),
      `remark` VARCHAR (100),
      PRIMARY KEY (`id`)
    );
    

    Yml

    application-sharding_table.yml

     
    server:
      port: 80
    spring:
      application:
        name: shardingJdbcDemo
      #shardingsphere相关配置
      shardingsphere:
        datasource:
          names: db   #库名,只是名字
          db: #数据源
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
        sharding: #指定表的分片规则
          tables: # 看到table "s" ,就知道可配置多个
            my_table: # 指定表名,此名必须和model中 @TableName(value = "my_table") 一致
              actualDataNodes: db.my_table_$->{0..1} #创建了两个表,下标0和1,所以此处配置你懂的
              tableStrategy:
                inline: # 指定表的分片策略
                  shardingColumn: id #参与分片运算的列名
                  algorithmExpression: my_table_$->{id % 2} #分片规则
              keyGenerator: # 指定表的主键生成策略
                type: SNOWFLAKE  #SNOWFLAKE
                column: id  #指定主键
        props:
          sql:
            show: true #输出日志
    

    至此配置完毕,运行效果见下方代码

    分库

    Yml

    application-sharding_db.yml

    spring:
      application:
        name: shardingJdbcDemo
      #shardingsphere相关配置
      shardingsphere:
        datasource:
          names: db1,db2   #库名,只是名字
          db1: #从库1
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          db2: #从库2
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
        sharding: #指定表的分片规则
          tables: # 看到table "s" ,就知道可配置多个
            my_table: # 指定表名,此名必须和model中 @TableName(value = "my_table") 一致
              actualDataNodes: db1.my_table
            pub_table:
              actualDataNodes: db2.pub_table
        props:
          sql:
            show: true #输出日志
    
    
    

    Java

    Table0Controller.java中新增方法

        @GetMapping("saveByShardingDb")
        public void saveByShardingDb(){
            table0Service.save(new Table0(){{setSource("source");setRemark("remark");}});
            pubTableService.save(new PubTable(){{setSource("source");setRemark("remark");}});
        }
    

    测试后可看到数据该去哪去哪了

    分库分表

    java代码都不改,只改数据库及yml

    数据库

    master_db、 slave_db1、 slave_db2

    库中分别创建my_table_0、my_table_1,结构同 上

    Yml

    application-sharding_master_slave.yml

    spring:
      application:
        name: shardingJdbcDemo
      #shardingsphere相关配置
      shardingsphere:
        datasource:
          names: db0,db1,db2   #库名,只是名字
          db0: #主库
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          db1: #从库1
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          db2: #从库2
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
            #分库分表start
        sharding: #指定表的分片规则
          tables: # 看到table "s" ,就知道可配置多个
            my_table: # 指定表名,此名必须和model中 @TableName(value = "my_table") 一致
              actualDataNodes: db$->{0..2}.my_table_$->{0..1} #创建了两个表,下标0和1,所以此处配置你懂的
              databaseStrategy:
                inline: # 指定表的分片策略
                  shardingColumn: id #参与分片运算的列名
                  algorithmExpression: db$->{id % 3} #分片算法,分了三个库,所以要%3
              tableStrategy:
                inline: # 指定表的分片策略
                  shardingColumn: id #参与分片运算的列名
                  algorithmExpression: my_table_$->{id % 2} #分片算法
              keyGenerator: # 指定表的主键生成策略
                type: SNOWFLAKE  #SNOWFLAKE
                column: id  #指定主键
            #分库分表end
        props:
          sql:
            show: true #输出日志
    
    

    然后继续访问第一步的save&select方法就可看到效果了,配置文件中写的主从库没有实际意义,起错名字了,实际都会往里面写

    读写分离

    数据库

    模拟主从,不做MySql真正的主从同步

    上面做表分片时已经创建好了主库master_db 再创建两个库 slave_db1 slave_db2

    三个库表结构一致

    image-20210602134547999

    master_db表中无数据

    slave_db1 表数据如下

    ​ "id" "source" "remark"
    ​ "1" "source1" "remark1"

    slave_db2 表数据如下

    ​ "id" "source" "remark"
    ​ "1" "source2" "remark2"

    Yml

    application-master_slave.yml

    spring:
      application:
        name: shardingJdbcDemo
      #shardingsphere相关配置
      shardingsphere:
        datasource:
          names: masterdb,slavedb1,slavedb2   #库名,只是名字
          masterdb: #主库
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          slavedb1: #从库1
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          slavedb2: #从库2
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
    
        masterslave:
          name: dbs
          master-data-source-name: masterdb #主库
          slave-data-source-names: slavedb1,slavedb2 #多个从库
          load-balance-algorithm-type: ROUND_ROBIN #RANDOM随机  ROUND_ROBIN 轮训
        props:
          sql:
            show: true #输出日志
    

    这时,访问上面搭好的项目,即可进行读写分离,代码见上方链接

    其他

    只请求主库

    在请求上方添加如下代码即可

        //    HintManager hintManager = HintManager.getInstance();
         //   hintManager.setMasterRouteOnly();
    @GetMapping("select")
        public  PageInfo select(int pageNum,int pageSize,Long id){
        //    HintManager hintManager = HintManager.getInstance();
         //   hintManager.setMasterRouteOnly();
            PageHelper.startPage(pageNum,pageSize);
            QueryWrapper<Table0> queryWrapper=new QueryWrapper();
            if(!StringUtils.isEmpty(id)) {
                queryWrapper.eq("id", id);
            }
            List<Table0> list = table0Service.list(queryWrapper);
            PageInfo pageInfo = new PageInfo<>(list);
            return pageInfo;
        }
    

    读写分离判断逻辑代码

    大致的流程是shardingJdbc根据sql获得对应的sqlStatement,然后只有SelectStatement的才走从库

    /*
     * Licensed to the Apache Software Foundation (ASF) under one or more
     * contributor license agreements.  See the NOTICE file distributed with
     * this work for additional information regarding copyright ownership.
     * The ASF licenses this file to You under the Apache License, Version 2.0
     * (the "License"); you may not use this file except in compliance with
     * the License.  You may obtain a copy of the License at
     *
     *     http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.apache.shardingsphere.masterslave.route.engine.impl;
    
    import lombok.RequiredArgsConstructor;
    import org.apache.shardingsphere.api.hint.HintManager;
    import org.apache.shardingsphere.core.rule.MasterSlaveRule;
    import org.apache.shardingsphere.sql.parser.sql.statement.SQLStatement;
    import org.apache.shardingsphere.sql.parser.sql.statement.dml.SelectStatement;
    
    import java.util.ArrayList;
    
    /**
     * Data source router for master-slave.
     */
    @RequiredArgsConstructor
    public final class MasterSlaveDataSourceRouter {
        
        private final MasterSlaveRule masterSlaveRule;
        
        /**
         * Route.
         * 
         * @param sqlStatement SQL statement
         * @return data source name
         */
        public String route(final SQLStatement sqlStatement) {
            if (isMasterRoute(sqlStatement)) {
                MasterVisitedManager.setMasterVisited();
                return masterSlaveRule.getMasterDataSourceName();
            }
            return masterSlaveRule.getLoadBalanceAlgorithm().getDataSource(
                    masterSlaveRule.getName(), masterSlaveRule.getMasterDataSourceName(), new ArrayList<>(masterSlaveRule.getSlaveDataSourceNames()));
        }
        
        private boolean isMasterRoute(final SQLStatement sqlStatement) {
            return containsLockSegment(sqlStatement) || !(sqlStatement instanceof SelectStatement) || MasterVisitedManager.isMasterVisited() || HintManager.isMasterRouteOnly();
        }
        
        private boolean containsLockSegment(final SQLStatement sqlStatement) {
            return sqlStatement instanceof SelectStatement && ((SelecStatement) sqlStatement).getLock().isPresent();
        }
    }
    

    一主多从+分表

    上面实现了一主多从和表分片,现在把它整合到一起

    java代码还是没改,主要改的还是Yml

    Yml

    application-sharding_db_table_oneMaster_slaves.yml

    关键配置见 masterSlaveRule,分片配置未改

    #一主多从+表分片
    spring:
      application:
        name: shardingJdbcDemo
      #shardingsphere相关配置
      shardingsphere:
        datasource:
          names: db0,db1,db2   #库名,只是名字
          db0: #主库
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          db1: #从库1
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          db2: #从库2
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
        masterSlaveRule: # 这里配置这个规则的话,相当于是全局读写分离配置
          name: ds_rw # 名称,合法的字符串即可,但如果涉及到在读写分离的基础上设置分库分表,则名称需要有意义才可以,另外,虽然目前没有强制要求,但主从库配置需要配置在实际关联的主从库上,如果配置的数据源之间主从是断开的状态,那么可能会发生写入的数据对于只读会话无法读取到的问题
          # 如果一个会话发生了写入并且没有提交(显式打开事务),sharidng sphere在后续的路由中,select都会在主库执行,直到会话提交
          masterDataSourceName: db0 # 主库的DataSource名称
          slaveDataSourceNames: # 从库的DataSource列表,至少需要有一个
            - db1
            - db2
          loadBalanceAlgorithmType: ROUND_ROBIN #从库负载均衡算法类型,可选值:ROUND_ROBIN,RANDOM。若loadBalanceAlgorithmClassName存在则忽略该配置,默认为ROUND_ROBIN
        sharding: #指定表的分片规则
          tables: # 看到table "s" ,就知道可配置多个
            my_table: # 指定表名,此名必须和model中 @TableName(value = "my_table") 一致
              actualDataNodes: db$->{0..2}.my_table_$->{0..1} #创建了两个表,下标0和1,所以此处配置你懂的
              databaseStrategy:
                inline: # 指定表的分片策略
                  shardingColumn: id #参与分片运算的列名
                  algorithmExpression: db$->{id % 3} #分片算法,分了三个库,所以要%3
              tableStrategy:
                inline: # 指定表的分片策略
                  shardingColumn: id #参与分片运算的列名
                  algorithmExpression: my_table_$->{id % 2} #分片算法
              keyGenerator: # 指定表的主键生成策略
                type: SNOWFLAKE  #SNOWFLAKE
                column: id  #指定主键
        props:
          sql:
            show: true #输出日志
    
    

    一主多从+分库分表

    上面实现了一主多从和表分片,现在把它整合到一起

    java代码还是没改,主要改的还是Yml

    创建了两个主库两个从库master_db1、master_db2、slave_db1、slave_db2

    下方配置为 master_db1slave_db1为主从关系、master_db2与slave_db2为主从关系

    修改点有点多,查看标*****的位置

    参考

    Yml

    application-sharding_db_table_masters_slaves.yml

    #一主多从+表分片
    spring:
      application:
        name: shardingJdbcDemo
      #shardingsphere相关配置
      shardingsphere:
        datasource:
          names: db0,db1,db2,db3   #库名,只是名字 ******************新增名称db3
          db0: #主库                       
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/master_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          db1: #主库1                         ****************** 添加主库
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/master_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          db2: #从库1
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          db3: #从库2                          ******************添加从库
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
        sharding:
          master-slave-rules: # 新增配置 ******************
            db0: # 此处名字一定要配置和下面 master-data-source-name 名字一致的
              master-data-source-name: db0
              slave-data-source-names: db2
            db1: # 此处名字一定要配置和下面 master-data-source-name 名字一致的
              master-data-source-name: db1
              slave-data-source-names: db3
          tables: # 看到table "s" ,就知道可配置多个
            my_table: # 指定表名,此名必须和model中 @TableName(value = "my_table") 一致
              actualDataNodes: db$->{0..1}.my_table_$->{0..1} #******************每组有一主一从,所以是0..1
              databaseStrategy:
                inline: # 指定表的分片策略
                  shardingColumn: id #参与分片运算的列名
                  algorithmExpression: db$->{(id / 10).toBigInteger() % 2} # *******不能再用id%2方式了,会导致数据分配不均,所以需要自定义方法
              tableStrategy:
                inline: # 指定表的分片策略
                  shardingColumn: id #参与分片运算的列名
                  algorithmExpression: my_table_$->{id % 2} #分片算法
              keyGenerator: # 指定表的主键生成策略
                type: SNOWFLAKE  #SNOWFLAKE
                column: id  #指定主键
        props:
          sql:
            show: true #输出日志
    

    公共表&数据脱敏

    公共表

    项目中会有很多字典表、配置表等等,此类表数据固定、量级不大,所以可以无需采用分库分表,每个库存一份;

    当配置公共表后,每次对公共表进行操作,都会同步操作所有库中的公共表

    数据库

    分别在三个库中新增表pub_table

    Java代码

    生成pub_table相关的MybatisPlus代码

    Yml

    application-publicTable_encryptor.yml

    spring:
      application:
        name: shardingJdbcDemo
      #shardingsphere相关配置
      shardingsphere:
        datasource:
          names: db0,db1,db2   #库名,只是名字
          db0: #主库
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          db1: #从库1
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db1?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
          db2: #从库2
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/slave_db2?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
        sharding:
          default-data-source-name: db #如果有多个库,公共表只有一个库有,那么,就要指定有公共表的库,否则会报找不到表
          default-database-strategy:
            inline:
              sharding-column: id
              algorithm-expression: db$->{id % 3}
          broadcast-tables: pub_table #公共表配置,可以多个
        props:
          sql:
            show: true #输出日志
    

    数据脱敏

    参考

    spring:
      application:
        name: shardingJdbcDemo
      #shardingsphere相关配置
      shardingsphere:
        datasource:
          names: db   #库名,只是名字
          db: #数据源
            type: com.alibaba.druid.pool.DruidDataSource
            driverClassName: com.mysql.jdbc.Driver
            url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&serverTimezone=GMT
            username: root
            password: 123
        sharding: #指定表的分片规则
          # 数据脱敏规则配置---start
          encrypt-rule:
            encryptors:
              encryptor_MD5:
                type: MD5
                props:
                  md5.key.value: 123456
              encryptor_aes:
                # 加密、解密器的名字,内置的为MD5,aes.
                # 可以自定义,实现
                # org.apache.shardingsphere.encrypt.strategy.spi.Encryptor
                # 或者
                # org.apache.shardingsphere.encrypt.strategy.spi.QueryAssistedEncryptor
                # 这两个接口即可
                type: aes
                props:
                  aes.key.value: 123456
            tables:
              # tables
              my_table:
                columns:
                  # 逻辑列,就是写SQL里面的列,因为实体类的名字和数据库的加密列一致,所以这里都是name
                  source:
                    # 原文列
                    # plainColumn: password
                    # 密文列,用来存储密文数据
                    cipherColumn: source
                    # 加密器名字
                    encryptor: encryptor_MD5
                    #  password1:
                    # 原文列
                    #     plainColumn: password1
                    # 密文列,用来存储密文数据
                    #   cipherColumn: aes_password
                    # 加密器名字
                  #   encryptor: encryptor_aes
          # 数据脱敏规则配置---end
          broadcast-tables: pub_table #公共表
          tables: # 看到table "s" ,就知道可配置多个
            my_table: # 指定表名,此名必须和model中 @TableName(value = "my_table") 一致
              actualDataNodes: db.my_table_$->{0..1} #创建了两个表,下标0和1,所以此处配置你懂的
              tableStrategy:
                inline: # 指定表的分片策略
                  shardingColumn: id #参与分片运算的列名
                  algorithmExpression: my_table_$->{id % 2} #分片算法
              keyGenerator: # 指定表的主键生成策略
                type: SNOWFLAKE  #SNOWFLAKE
                column: id  #指定主键
        props:
          sql:
            show: true #输出日志
          query.with.cipher.column: true #是否使用密文列查询
    

    分布式事务

    分库分表后,因为不是一个库了,所以一旦报错,数据无法回滚

    Yml

    使用上方 application-sharding_db_table_masters_slaves.yml

    pom

            <!-- 使用 XA 事务时,需要引入此模块 -->
            <dependency>
                <groupId>io.shardingsphere</groupId>
                <artifactId>sharding-transaction-spring-boot-starter</artifactId>
                <version>3.1.0</version>
                <type>pom</type>
            </dependency>
    

    Java

    新增

    package com.rollback.shardingjdbcdemo.demo.conf;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.sql.DataSource;
    
    @Configuration
    @EnableTransactionManagement
    public class TransactionConfiguration {
    
        @Bean
        public PlatformTransactionManager txManager(final DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    
        @Bean
        public JdbcTemplate jdbcTemplate(final DataSource dataSource) {
            return new JdbcTemplate(dataSource);
        }
    }
    

    修改save方法

    saveByTransaction

    package com.rollback.shardingjdbcdemo.demo.sharding.controller;
    
    
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.github.pagehelper.PageHelper;
    import com.github.pagehelper.PageInfo;
    import com.rollback.shardingjdbcdemo.demo.sharding.model.Table0;
    import com.rollback.shardingjdbcdemo.demo.sharding.service.Table0Service;
    import org.apache.shardingsphere.api.hint.HintManager;
    import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
    import org.apache.shardingsphere.transaction.core.TransactionType;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.util.StringUtils;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    import java.util.Random;
    
    /**
     * <p>
     *  前端控制器
     * </p>
     *
     * @author koala
     * @since 2021-05-31
     */
    @RestController
    @RequestMapping("/table0")
    public class Table0Controller {
        @Autowired
        Table0Service table0Service;
    
        @GetMapping("save")
        public void save(int tag){
                table0Service.save(new Table0(){{setSource("source"+tag);setRemark("remark"+tag);}});
        }
        @Transactional
        @ShardingTransactionType(TransactionType.XA)  // 支持TransactionType.LOCAL, TransactionType.XA, TransactionType.BASE
        @GetMapping("saveByTransaction")
        public void saveByTransaction(int tag){
            for (int i = 0; i < 10; i++) {
                if(i==5){
                    List list=null;
                    list.add("error");
                }
                table0Service.save(new Table0(){{setSource("source"+tag);setRemark("remark"+tag);}});
            }
        }
    
        @GetMapping("select")
        public  PageInfo select(int pageNum,int pageSize,Long id){
    //        HintManager hintManager = HintManager.getInstance();
    //        hintManager.setMasterRouteOnly();
            PageHelper.startPage(pageNum,pageSize);
            QueryWrapper<Table0> queryWrapper=new QueryWrapper();
            if(!StringUtils.isEmpty(id)) {
                queryWrapper.eq("id", id);
            }
            queryWrapper.eq("source","source1");
            List<Table0> list = table0Service.list(queryWrapper);
            PageInfo pageInfo = new PageInfo<>(list);
            return pageInfo;
        }
    
        @GetMapping("select1")
        public  List<Table0> select1(int pageNum,int pageSize,Long id){
            QueryWrapper<Table0> queryWrapper=new QueryWrapper();
            if(!StringUtils.isEmpty(id)) {
                queryWrapper.eq("id", id);
            }
            //queryWrapper.eq("source","source1");
            List<Table0> list = table0Service.list(queryWrapper);
            return list;
        }
    }
    

    验证步骤:

    • 清空数据库

    • 执行saveByTransaction

    • 报错后观察数据库,一条都没有

    • 去掉

      ​ @Transactional
      ​ @ShardingTransactionType(TransactionType.XA) // 支持TransactionType.LOCAL, TransactionType.XA, TransactionType.BASE

      后,会出现保存部分数据的情况

    参考官网

    代码下载

    代码见sharding包下,请求入口见 Table0Controller

    1.所写技术都是我工作中用到的
    2.所写技术都是自己从项目中提取的
    3.所有配置搭建流程都经过2到3遍的测试
    4.因都是工作中使用的技术,所以不确定是否有转载的,如果有,请及时通知
  • 相关阅读:
    挑战程序设计竞赛 dp
    算法导论 动态规划
    算法导论第二章
    divide conquer
    时间戳
    bootstrap 针对超小屏幕和中等屏幕设备定义的不同的类
    jQuery中的Ajax
    怎么判断一个变量是Null还是undefined
    认识Ajax
    关于apache
  • 原文地址:https://www.cnblogs.com/rb2010/p/14859881.html
Copyright © 2011-2022 走看看