sharding-JDBC分库分表配置分析

什么是ShardingSphere

Apache ShardingSphere 由 JDBC、Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成。 它们均提供标准化的基于数据库作为存储节点的增量功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。
详细资料点击官网地址.

分库分表解决什么问题

    • 为什么要分库分表?
    • 分库分表就是为了解决由于数据量(比如电商的订单)过大而导致数据库性能(CPU、内存、磁盘、网络)降低的问题,将原本单个数据库拆分成多个数据库 ,将数据量大的表拆分成若干个数据表,使得单一数据库、单一数据表的数据量变小,从而达到提升数据库性能的目的。
    • 分库分表的四种方式:垂直分库、垂直分表、水平分库和水平分表
      • 垂直分库:
      • 通过将表按业务分类,然后分布在不同数据库,并且可以将这些数据库部署在不同服务器上,从而达到多个服务器共同分摊压力的效果,大大提高性能。但是依然没有解决单表数据量过大的问题,且需要解决跨库带来的复杂性问题。
      • 垂直分表:
      • 把一个字段比较多的表按照字段访问频次冷热程度、是否是大字段的原则拆分为多个表,这样既能使业务清晰,还能提升部分性能。拆分后,尽量从业务角度避免联查,否则性能方面将得不偿失。
      • 水平分库:
      • 把一张表的数据(数据行)按一定规则拆分到不同的数据库中,每个库只有这个表的部分数据,这些数据库可以分布在不同的服务器上,从而使访问压力被多服务器负载,提升性能。它不仅需要解决跨库带来的问题,还需要解决数据路由的问题。
      • 水平分表:
      • 把一张表的数据(数据行)分到多个同一个数据库的多张表中,每个表只有这个表的部分数据,解决单表数据量过大而产生的性能问题,它仅仅作为水平分库的一个补充优化。
      • 数据库相关优化方案

        • 软件层面包括:SQL调优、表结构优化、读写分离、数据库集群、分库分表等。
        • 硬件层面主要是增加机器性能。
        如果出现数据库问题不要着急分库分表,分库分表会给系统带来巨大的复杂性,不到万不得已前提下建议不要使用分库分表。

        两种情况下:

        • 当数据量随着业务量的提升不断增大,但访问数据库压力不是特别大的情况下,我们首先考虑缓存、读写分离、索引等技术方案。
        • 当数据量特别大并且持续增长时,即将或者已经出现性能瓶颈时,可以考虑分库分表方案。
        更加详细的可以看这两篇文章:

        分库分表解决方案.

        面试必备SQL调优方案.

        Springboot整合Sharding-JDBC

        ShardingJDBC简介

        定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。

        • 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC。
        • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, HikariCP 等。
        • 支持任意实现 JDBC 规范的数据库,目前支持 MySQL,PostgreSQL,Oracle,SQLServer 以及任何可使用 JDBC 访问的数据库。

        Sharding-JDBC核心配置

        在这里插入图片描述

        • 分片规则
        • 分片规则配置的总入口。包含数据源配置、表配置、绑定表配置以及读写分离配置等
        • 数据源配置
        • 真实数据源列表
        • 表配置
        • 逻辑表名称、数据节点与分表规则的配置
        • 数据节点配置
        • 用于配置逻辑表与真实表的映射关系。可分为均匀分布和自定义分布两种形式
        • 分片策略配置

          对于分片策略存有数据源分片策略和表分片策略两种维度

          • 数据源分片策略
          • 对应于DatabaseShardingStrategy。用于配置数据被分配的目标数据源
          • 表分片策略
          • 对应于TableShardingStrategy。用于配置数据被分配的目标表,该目标表存在与该数据的目标数据源内。故表分片策略是依赖与数据源分片策略的结果的
        • 自增主键生成策略
        • 通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。

        SpringBoot整合Sharding-JDBC实现代码

        在这里我们主要基于JavaConfig配置的方式来集成到SpringBoot中,代码如下:

        1、pom文件中添加Sharding-JDBC和MySQL驱动依赖,以及其他的相关依赖,我这里使用的是阿里巴巴Druid数据库连接池。

            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                    <version>${spring-boot.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-test</artifactId>
                    <version>${spring-boot.version}</version>
                    <scope>test</scope>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-aop</artifactId>
                    <version>${spring-boot.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context-support</artifactId>
                    <version>${spring.version}</version>
                </dependency>
                <dependency>
                    <groupId>com.github.pagehelper</groupId>
                    <artifactId>pagehelper-spring-boot-starter</artifactId>
                    <version>${pagehelper.version}</version>
                </dependency>
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>${mysql.version}</version>
                </dependency>
                <dependency>
                    <groupId>com.alibaba</groupId>
                    <artifactId>druid-spring-boot-starter</artifactId>
                    <version>${druid.version}</version>
                </dependency>
                <dependency>
                    <groupId>joda-time</groupId>
                    <artifactId>joda-time</artifactId>
                    <version>${joda.time.version}</version>
                </dependency>
                <dependency>
                    <groupId>com.alibaba</groupId>
                    <artifactId>fastjson</artifactId>
                    <version>${fastjson.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.apache.shardingsphere</groupId>
                    <artifactId>sharding-jdbc-core</artifactId>
                    <scope>compile</scope>
                    <exclusions>
                        <exclusion>
                            <groupId>ch.qos.logback</groupId>
                            <artifactId>logback-classic</artifactId>
                        </exclusion>
                    </exclusions>
                    <version>4.1.1</version>
                </dependency>
                <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
                <dependency>
                    <groupId>org.apache.curator</groupId>
                    <artifactId>curator-recipes</artifactId>
                    <version>4.2.0</version>
                </dependency>
                <dependency>
                    <groupId>commons-io</groupId>
                    <artifactId>commons-io</artifactId>
                </dependency>
            </dependencies>
        

        2、配置数据源(两个数据库)

        spring:
          shardingsphere:
          datasource:
            # 数据源:shard_one
            dataOne:
              type: com.alibaba.druid.pool.DruidDataSource
              druid:
                driverClassName: com.mysql.jdbc.Driver
                url: jdbc:mysql://localhost:3306/shard_one?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false
                username: root
                password: 123456
                initial-size: 10
                max-active: 100
                min-idle: 10
                max-wait: 60000
                pool-prepared-statements: true
                max-pool-prepared-statement-per-connection-size: 20
                time-between-eviction-runs-millis: 60000
                min-evictable-idle-time-millis: 300000
                max-evictable-idle-time-millis: 60000
                validation-query: SELECT 1 FROM DUAL
                # validation-query-timeout: 5000
                test-on-borrow: false
                test-on-return: false
                test-while-idle: true
                connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
            # 数据源:shard_two
            dataTwo:
              type: com.alibaba.druid.pool.DruidDataSource
              druid:
                driverClassName: com.mysql.jdbc.Driver
                url: jdbc:mysql://localhost:3306/shard_two?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false
                username: root
                password: 123456
                initial-size: 10
                max-active: 100
                min-idle: 10
                max-wait: 60000
                pool-prepared-statements: true
                max-pool-prepared-statement-per-connection-size: 20
                time-between-eviction-runs-millis: 60000
                min-evictable-idle-time-millis: 300000
                max-evictable-idle-time-millis: 60000
                validation-query: SELECT 1 FROM DUAL
                # validation-query-timeout: 5000
                test-on-borrow: false
                test-on-return: false
                test-while-idle: true
                connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
        

        3、创建两个数据库dataOne的实例

        public class TableOne {
            private Long id;
        
            private String phone;
        
            private String name;
        
            public Long getId() {
                return id;
            }
        
            public void setId(Long id) {
                this.id = id;
            }
        
            public String getPhone() {
                return phone;
            }
        
            public void setPhone(String phone) {
                this.phone = phone;
            }
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public String getSex() {
                return sex;
            }
        
            public void setSex(String sex) {
                this.sex = sex;
            }
        
            private String sex;
        
        }
        

        4、创建TableOne数据访问接口

        public interface TableOneService {
            void createTable () ;
            void insertOne () ;
            List<TableOne> selectOneByPhone (String phone) ;
        }
        

        5、创建TableOne数据访问实现类

        @Service
        public class TableOneServiceImpl implements TableOneService {
        
            @Resource
            private TableOneMapper tableOneMapper ;
        
            @Autowired
            @Qualifier("dataOneTemplate")
            private JdbcTemplate dataOneTemplate ;
        
            @Autowired
            @Qualifier("dataTwoTemplate")
            private JdbcTemplate dataTwoTemplate ;
        
            @Override
            public void createTable() {
                for (int i = 1 ; i <= 5 ; i++){
                    String executeSQL = "CREATE TABLE table_one_"+i+" (\n" +
                            "  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',\n" +
                            "  `phone` varchar(20) NOT NULL COMMENT '手机号',\n" +
                            "  `name` varchar(50) DEFAULT NULL COMMENT '备用1',\n" +
                            "  `sex` varchar(50) DEFAULT NULL COMMENT '备用2',\n" +
                            "  PRIMARY KEY (`id`),\n" +
                            "  KEY `phoneIndex` (`phone`)\n" +
                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8;" ;
                    dataOneTemplate.execute(executeSQL);
                    dataTwoTemplate.execute(executeSQL);
                }
            }
        
            @Override
            public void insertOne() {
                for (int i = 0 ; i < 20 ; i++){
                    Long id = new SnowFlake(5,6).nextId(false);
                    TableOne tableOne = new TableOne() ;
                    tableOne.setId(id);
                    tableOne.setPhone("188136777"+i);
                    tableOne.setName("张三"+i);
                    tableOne.setSex("男");
                    tableOneMapper.insert(tableOne) ;
                }
            }
        
            @Override
            public List<TableOne> selectOneByPhone(String phone) {
                return tableOneMapper.selectOneByPhone(phone);
            }
        }
        
        

        6、创建Mapper接口以及实现SQL操作

        @Mapper
        public interface TableOneMapper {
        
            List<TableOne> selectOneByPhone (@Param("phone") String phone) ;
        
            int insert(TableOne record);
        
        }
        
        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
        <mapper namespace="com.shard.jdbc.mapper.TableOneMapper" >
          <resultMap id="BaseResultMap" type="com.shard.jdbc.entity.TableOne" >
            <id column="id" property="id"/>
            <result column="phone" property="phone"/>
            <result column="name" property="name"/>
            <result column="sex" property="sex"/>
          </resultMap>
          <sql id="Base_Column_List" >
            id, phone, name, sex
          </sql>
        
          <select id="selectOneByPhone" resultMap="BaseResultMap">
            select
            <include refid="Base_Column_List" />
            from table_one
            where phone = #{phone}
          </select>
        
          <insert id="insert" parameterType="com.shard.jdbc.entity.TableOne" useGeneratedKeys="true" keyProperty="id" >
            insert into table_one (id,phone, name, sex)
            values (#{phone,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
              #{sex,jdbcType=VARCHAR})
          </insert>
        
        </mapper>
        

        7、数据库分库分表配置()
        7.1 连接数据源

            /**
             * shard_one数据源
             */
            @Value("${spring.datasource.dataOne.druid.url}")
            private String dbUrl1;
            @Value("${spring.datasource.dataOne.druid.username}")
            private String username1;
            @Value("${spring.datasource.dataOne.druid.password}")
            private String password1;
            @Value("${spring.datasource.dataOne.druid.driverClassName}")
            private String driverClassName1;
            @Value("${spring.datasource.dataOne.druid.initial-size}")
            private int initialSize1;
            @Value("${spring.datasource.dataOne.druid.max-active}")
            private int maxActive1;
            @Value("${spring.datasource.dataOne.druid.min-idle}")
            private int minIdle1;
            @Value("${spring.datasource.dataOne.druid.max-wait}")
            private int maxWait1;
            @Value("${spring.datasource.dataOne.druid.pool-prepared-statements}")
            private boolean poolPreparedStatements1;
            @Value("${spring.datasource.dataOne.druid.max-pool-prepared-statement-per-connection-size}")
            private int maxPoolPreparedStatementPerConnectionSize1;
            @Value("${spring.datasource.dataOne.druid.time-between-eviction-runs-millis}")
            private int timeBetweenEvictionRunsMillis1;
            @Value("${spring.datasource.dataOne.druid.min-evictable-idle-time-millis}")
            private int minEvictableIdleTimeMillis1;
            @Value("${spring.datasource.dataOne.druid.max-evictable-idle-time-millis}")
            private int maxEvictableIdleTimeMillis1;
            @Value("${spring.datasource.dataOne.druid.validation-query}")
            private String validationQuery1;
            @Value("${spring.datasource.dataOne.druid.test-while-idle}")
            private boolean testWhileIdle1;
            @Value("${spring.datasource.dataOne.druid.test-on-borrow}")
            private boolean testOnBorrow1;
            @Value("${spring.datasource.dataOne.druid.test-on-return}")
            private boolean testOnReturn1;
            @Value("{spring.datasource.dataOne.druid.connection-properties}")
            private String connectionProperties1;
            @Bean
            public DruidDataSource dataOneSource() {
                DruidDataSource datasource = new DruidDataSource();
                datasource.setUrl(dbUrl1);
                datasource.setUsername(username1);
                datasource.setPassword(password1);
                datasource.setDriverClassName(driverClassName1);
                datasource.setInitialSize(initialSize1);
                datasource.setMinIdle(minIdle1);
                datasource.setMaxActive(maxActive1);
                datasource.setMaxWait(maxWait1);
                datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis1);
                datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis1);
                datasource.setMaxEvictableIdleTimeMillis(minEvictableIdleTimeMillis1);
                datasource.setValidationQuery(validationQuery1);
                datasource.setTestWhileIdle(testWhileIdle1);
                datasource.setTestOnBorrow(testOnBorrow1);
                datasource.setTestOnReturn(testOnReturn1);
                datasource.setPoolPreparedStatements(poolPreparedStatements1);
                datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize1);
                datasource.setConnectionProperties(connectionProperties1);
                return datasource;
            }
        
            /**
             * shard_two数据源
             */
            @Value("${spring.datasource.dataTwo.druid.url}")
            private String dbUrl2;
            @Value("${spring.datasource.dataTwo.druid.username}")
            private String username2;
            @Value("${spring.datasource.dataTwo.druid.password}")
            private String password2;
            @Value("${spring.datasource.dataTwo.druid.driverClassName}")
            private String driverClassName2;
            @Value("${spring.datasource.dataTwo.druid.initial-size}")
            private int initialSize2;
            @Value("${spring.datasource.dataTwo.druid.max-active}")
            private int maxActive2;
            @Value("${spring.datasource.dataTwo.druid.min-idle}")
            private int minIdle2;
            @Value("${spring.datasource.dataTwo.druid.max-wait}")
            private int maxWait2;
            @Value("${spring.datasource.dataTwo.druid.pool-prepared-statements}")
            private boolean poolPreparedStatements2;
            @Value("${spring.datasource.dataTwo.druid.max-pool-prepared-statement-per-connection-size}")
            private int maxPoolPreparedStatementPerConnectionSize2;
            @Value("${spring.datasource.dataTwo.druid.time-between-eviction-runs-millis}")
            private int timeBetweenEvictionRunsMillis2;
            @Value("${spring.datasource.dataTwo.druid.min-evictable-idle-time-millis}")
            private int minEvictableIdleTimeMillis2;
            @Value("${spring.datasource.dataTwo.druid.max-evictable-idle-time-millis}")
            private int maxEvictableIdleTimeMillis2;
            @Value("${spring.datasource.dataTwo.druid.validation-query}")
            private String validationQuery2;
            @Value("${spring.datasource.dataTwo.druid.test-while-idle}")
            private boolean testWhileIdle2;
            @Value("${spring.datasource.dataTwo.druid.test-on-borrow}")
            private boolean testOnBorrow2;
            @Value("${spring.datasource.dataTwo.druid.test-on-return}")
            private boolean testOnReturn2;
            @Value("{spring.datasource.dataTwo.druid.connection-properties}")
            private String connectionProperties2;
            @Bean
            public DruidDataSource dataTwoSource() {
                DruidDataSource datasource = new DruidDataSource();
                datasource.setUrl(dbUrl2);
                datasource.setUsername(username2);
                datasource.setPassword(password2);
                datasource.setDriverClassName(driverClassName2);
                datasource.setInitialSize(initialSize2);
                datasource.setMinIdle(minIdle2);
                datasource.setMaxActive(maxActive2);
                datasource.setMaxWait(maxWait2);
                datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis2);
                datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis2);
                datasource.setMaxEvictableIdleTimeMillis(minEvictableIdleTimeMillis2);
                datasource.setValidationQuery(validationQuery2);
                datasource.setTestWhileIdle(testWhileIdle2);
                datasource.setTestOnBorrow(testOnBorrow2);
                datasource.setTestOnReturn(testOnReturn2);
                datasource.setPoolPreparedStatements(poolPreparedStatements2);
                datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize2);
                datasource.setConnectionProperties(connectionProperties2);
                return datasource;
            }
        

        7.2 JDBC操作配置(这里主要用于自定义创建表,controller层中)

            @Bean(name = "dataOneTemplate")
            public JdbcTemplate dataOneTemplate (@Autowired DruidDataSource dataOneSource){
                return new JdbcTemplate(dataOneSource) ;
            }
            @Bean(name = "dataTwoTemplate")
            public JdbcTemplate dataTwoTemplate (@Autowired DruidDataSource dataTwoSource){
                return new JdbcTemplate(dataTwoSource) ;
            }
        

        如下图:
        在这里插入图片描述
        7.3 Shard-JDBC 分库分表配置

            @Bean
            public DataSource dataSource (@Autowired DruidDataSource dataOneSource,
                                          @Autowired DruidDataSource dataTwoSource) throws Exception {
                ShardingRuleConfiguration shardJdbcConfig = new ShardingRuleConfiguration();
                // 配置分库分表规则
                shardJdbcConfig.getTableRuleConfigs().add(getTableRule01());
                shardJdbcConfig.getTableRuleConfigs().add(getTableRule02());
                //配置默认数据源
                shardJdbcConfig.setDefaultDataSourceName("ds_0");
                //绑定表的关联
               shardJdbcConfig.getBindingTableGroups().add("table_one,table_two");
                //2配置读写分离规则
                /*shardingRuleConfig.setMasterSlaveRuleConfigs();*/
               //指定需要分库分表的数据源
                Map<String,DataSource> dataMap = new LinkedHashMap<>() ;
                dataMap.put("ds_0",dataOneSource) ;
                dataMap.put("ds_1",dataTwoSource) ;
                //属性配置项,可以为以下属性
                Properties prop = new Properties();
                //是否打印SQL解析和改写日志
                prop.setProperty("sql.show",Boolean.TRUE.toString());
                //用于SQL执行的工作线程数量,为零则表示无限制
                prop.setProperty("executor.size","4");
                //每个物理数据库为每次查询分配的最大连接数量
                prop.setProperty("max.connections.size.per.query","1");
                //是否在启动时检查分表元数据一致性
                prop.setProperty("check.table.metadata.enabled","false");
                return ShardingDataSourceFactory.createDataSource(dataMap, shardJdbcConfig,prop);
            }
        

        这里需要注意一点是表的绑定:
        //绑定表的关联
        shardJdbcConfig.getBindingTableGroups().add(“table_one,table_two”);

        指分片规则一致的主表和子表。 例如:t_order 表和 t_order_item 表,均按照 order_id 分片,则此两张表互为绑定表关系。 绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。 举例说明,如果 SQL 为:

        SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
        

        在不配置绑定表关系时,假设分片键 order_id 将数值 10 路由至第 0 片,将数值 11 路由至第 1 片,那么路由后的 SQL 应该为 4 条,它们呈现为笛卡尔积:

        SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
        
        SELECT i.* FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
        
        SELECT i.* FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
        
        SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
        

        在配置绑定表关系后,路由的 SQL 应该为 2 条:

        SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
        
        SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
        

        其中 t_order 在 FROM 的最左侧,ShardingSphere 将会以它作为整个绑定表的主表。 所有路由计算将会只使用主表的策略,那么 t_order_item 表的分片计算将会使用 t_order 的条件。 因此,绑定表间的分区键需要完全相同。

        7.4 Shard-JDBC 分表配置

            private static TableRuleConfiguration getTableRule01() {
                // param1 : 逻辑表名, param2 : 真实存在的节点,由数据源 + 表名组成, ds${0..1} 代表 数据库选择 ds 后缀为 0 - 1 之间,table_one 代表数据表 table_one 后缀 1 - 5 之间
                TableRuleConfiguration result = new TableRuleConfiguration("table_one","ds_${0..1}.table_one_${1..5}");
                //主键生成列,默认的主键生成算法是snowflake
                result.setKeyGeneratorConfig(getKeyGeneratorConfiguration());
                // 设置数据源分片规则
                //设置分片策略,这里简单起见直接取模,也可以使用自定义算法来实现分片规则
                result.setDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("phone", new DataSourceAlg()));
                // 设置数据表分片规则
                //设置分片策略,这里简单起见直接取模,也可以使用自定义算法来实现分片规则
                result.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("phone", new TableOneAlg()));
                return result;
            }
            private static TableRuleConfiguration getTableRule02() {
                // param1 : 逻辑表名, param2 : 真实存在的节点,由数据源 + 表名组成, ds${0..1} 代表 数据库选择 ds 后缀为 0 - 1 之间,table_two 代表数据表 table_two 后缀 1 - 5 之间
                TableRuleConfiguration result = new TableRuleConfiguration("table_two","ds_${0..1}.table_two_${1..5}");
                //主键生成列,默认的主键生成算法是snowflake
                result.setKeyGeneratorConfig(getKeyGeneratorConfiguration());
                // 设置数据源分片规则
                //设置分片策略,这里简单起见直接取模,也可以使用自定义算法来实现分片规则
                result.setDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("phone", new DataSourceAlg()));
                // 设置数据表分片规则
                //设置分片策略,这里简单起见直接取模,也可以使用自定义算法来实现分片规则
                result.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("phone", new TableTwoAlg()));
                return result;
            }
        
        • getTableRule01和getTableRule02方法都是指定数据库的逻辑表和真实表以及数据写入指定数据库当中
      • 配置数据库分片策略
      • result.setDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration(“phone”, new DataSourceAlg()));

        public class DataSourceAlg implements PreciseShardingAlgorithm<String> {
        
           private static Logger LOG = LoggerFactory.getLogger(DataSourceAlg.class);
           @Override
           public String doSharding(Collection<String> names, PreciseShardingValue<String> value) {
               LOG.debug("分库算法参数 {},{}",names,value);
               int hash = HashUtil.rsHash(String.valueOf(value.getValue()));
               return "ds_" + ((hash % 2)) ;
           }
        }
        

        分片采用行表达式分片策略,代码中分片主键为phone,根据phone的hash计算分配到不同的数据库中,规则为:根据phone和2取模,将数据分别存入数据库shard_one和shard_two当中。

      • 配置表分片策略
      • result.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration(“phone”, new TableTwoAlg()));

        public class TableTwoAlg implements PreciseShardingAlgorithm<String> {
        
            private static Logger LOG = LoggerFactory.getLogger(TableTwoAlg.class);
        
        
            @Override
            public String doSharding(Collection<String> names, PreciseShardingValue<String> value) {
                LOG.info("参数:{},{}",names,value);
                int hash = HashUtil.rsHash(String.valueOf(value.getValue()));
                LOG.info("数据存入的表table_two_{}",(hash % 5+1));
                return "table_two_" + (hash % 5+1);
            }
        }
        

        这里以table_two表说明(table_one规则一样),
        分表以phone为分片键进行分表,分片算法为PreciseShardingAlgorithm.
        collection中存的表名table_two_1…table_two_5,根据 int hash = HashUtil.rsHash(String.valueOf(value.getValue()));计算得到的值决定将当前数据存入哪个表中,
        执行sql语句如下:

        在这里插入图片描述

        7.5 主键生成列(雪花算法)

            public static KeyGeneratorConfiguration getKeyGeneratorConfiguration(){
                KeyGeneratorConfiguration result = new KeyGeneratorConfiguration("SNOWFLAKE","id");
                return result;
        
            }
        
      • 2
        点赞
      • 4
        收藏
        觉得还不错? 一键收藏
      • 0
        评论
      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值