67 ShardingSphere 分表分库

1,什么是垂直/水平拆分模式

2,基于客户端与服务器端实现分表分库的区别

3,单表达到多大的量开始分表分库
4,数据库分表分库策略有哪些
5, shardingSphere 实战分库分表
6,为什么不推荐使用mycat 实现分库分表
7,分表分库后查询存在哪些优缺点
8,分表分库后如何实现分页查询
9,分表分库后如何实现排序查询;

垂直/水平拆分模式
1,数据库拆分主要指分库分表,其目的主要是分散数据库压力,达到横向发展,满足均衡访问等。
2, 数据库拆分主要有2种形式: 垂直拆分和水平拆分。
A 垂直拆分:
将不同的业务功能相关的表放到不同的数据库中,也就是类似于 微服务架构中 会员数据库/订单数据库/支付数据库
B 水平拆分:
当一张表的业务量行数如果超过 500 行,分页/排序效率还是非常低,可以对同一个表数据实现拆分放到多个不同的数据库表中存放。

Mayikt_memberdb01
Mayikt_user
Mayikt_memberdb02
Mayikt_user

基于客户端与服务器端实现分表分库的区别:

1,基于服务器端mycat 实现数据库代理
优点: 能够保证数据库 的安全性
缺点: 效率比较低

image.png

2,基于客户端Shardingjdbc 实现数据库代理:
优点: 效率比较高
缺点: 不能够保证数据库的安全性,内存溢出;


image.png

单表达到多大量开始分表分库:
【推荐】单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。
说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
摘自:阿里巴巴java开发手册

数据库分表分库策略有哪些:

取余/取模 均匀存放数据 缺点: 不够扩容。
按照范围分片: 1-500万 501万-10000万;
按照日期进行分片 日志,订单信息 同居
按照枚举值分片;
二进制取模范围分片:
一致性hash 分片,类似于HashMap 缺点 数据存放不均匀。
按照目前字段前缀指定的进行分区 mayikt wuhan
按照前缀ASCII 码和值进行取模范围分片。

主流分片算法: 取余/取模 日期 一致性hash 分片
根据user_id
Userid=1%2=1
Userid=2%2=0
Userid=3%2=1
Userid=4%2=0

不能实现扩容。

ShardingSphere 实战分表分库
ShardingSphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC, Sharding-PROXY 和 Sahriding 这三款 相互独立的产品组成。
他们均提供标准化的数据分片,分布式事务 和数据库治理功能,可适用于java同构,已购语言,云原生等各种多样化的应用场景。

image.png

Sharding_JDBC 可以实现
分库 & 分表

  • 读写分离
  • 分片策略定制化
  • 无中心化分布式主键

SharingdSphere 环境搭建:
数据库准备;

DROP TABLE IF EXISTS `mayikt_user_0`;
CREATE TABLE `mayikt_user_0` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of mayikt_user_0
-- ----------------------------
INSERT INTO `mayikt_user_0` VALUES ('2', 'mayikt2', '2');
INSERT INTO `mayikt_user_0` VALUES ('4', 'mayikt4', '4');
INSERT INTO `mayikt_user_0` VALUES ('6', 'mayikt6', '6');
INSERT INTO `mayikt_user_0` VALUES ('8', 'mayikt8', '8');

-- ----------------------------
-- Table structure for mayikt_user_1
-- ----------------------------
DROP TABLE IF EXISTS `mayikt_user_1`;
CREATE TABLE `mayikt_user_1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of mayikt_user_1
-- ----------------------------
INSERT INTO `mayikt_user_1` VALUES ('1', 'mayikt1', '1');
INSERT INTO `mayikt_user_1` VALUES ('3', 'mayikt3', '3');
INSERT INTO `mayikt_user_1` VALUES ('5', 'mayikt5', '5');
INSERT INTO `mayikt_user_1` VALUES ('7', 'mayikt7', '7');
INSERT INTO `mayikt_user_1` VALUES ('9', 'mayikt9', '9');



Maven 依赖:


<?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 https://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.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.taotao</groupId>
    <artifactId>sharding-jdbc</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sharding-jdbc</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>io.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>io.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-namespace</artifactId>
            <version>3.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>


application.yml 配置文件

# 数据源 mayiktdb
sharding:
  jdbc:
    datasource:
      names: shard1,shard2
      # 第一个数据库
      shard1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:3306/mayikt-member?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
        username: root
        password: root
      shard2:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:3306/mayikt?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
        username: root
        password: root
    # 水平拆分的数据库(表) 配置分库 + 分表策略 行表达式分片策略
    config:
      sharding:
        #默认数据源(未设置分表策略的表将默认用此数据源)
        default-database-name: shard1
        #默认分库策略
        default-database-strategy:
           standard:
             sharding-column: id
             precise-algorithm-class-name: com.taotao.rfspringboot.config.DataBasePreciseRule
        tables:
          mayikt_user:  ##虚拟表名称  mayikt_user_0 mayikt_user_1
            actual-data-nodes: shard$->{1..2}.mayikt_user_$->{0..2}  # 没有带上 分片字段
            table-strategy:
              standard:  ##SELECT * FROM  mayikt_user_1 where id =1
                precise-algorithm-class-name: com.taotao.rfspringboot.config.MayiktRangeShardingAlgorithm
                sharding-column: id
      # 打印执行的数据库
      props:
        sql:
          show: true

# 打印执行的sql语句
spring:
  main:
    allow-bean-definition-overriding: true
server:
  port: 8081

mybatis-plus:
  # 如果是放在src/main/java目录下 classpath:/com/yourpackage/*/com.exchange.mapper/*Mapper.com.exchange.mapper
  # 如果是放在resource目录 classpath:/com.exchange.mapper/*Mapper.com.exchange.mapper
  mapper-locations: classpath:/mapper/*.xml
  #实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: com.taotao.rfspringboot.entity
  global-config:
    #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
    #若采用雪花算法生成id,需要在生成的实体类中将id的type = IdType.AUTO去掉
    id-type: 0
    #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
    field-strategy: 2
    #驼峰下划线转换
    db-column-underline: true
    #刷新mapper 调试神器
    #refresh-mapper: true
    #数据库大写下划线转换
    #capital-mode: true
    # Sequence序列接口实现类配置
    #逻辑删除配置(下面3个配置)
    logic-delete-value: Y
    logic-not-delete-value: N
    #sql-injector: com.nky.pork.quality.standard.conf.MybatisPlusConfig
    configuration:
      #配置返回数据库(column下划线命名&&返回java实体是驼峰命名),自动匹配无需as(没开启这个,SQL需要写as: select user_id as userId)
      map-underscore-to-camel-case: true
      cache-enabled: false
      #配置JdbcTypeForNull, oracle数据库必须配置
      jdbc-type-for-null: 'null'

entity:

package com.taotao.shardingjdbc.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 *@author tom
 *Date  2020/11/6 0006 8:27
 *
 */
@Data
@TableName("mayikt_user")
public class Mayikt_user {
    private Integer id;
    private String name;
    private Integer age;

    public Mayikt_user(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}



数据库访问:

package com.taotao.shardingjdbc.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.taotao.shardingjdbc.entity.MayiktUser;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 *@author tom
 *Date  2020/11/6 0006 8:29
 *
 */
public interface MayiktUserMapper  extends BaseMapper<MayiktUser> {
    /**
     * 查询所有
     *
     * @return
     */
    @Select("SELECT * FROM mayikt_user")
    List<MayiktUser> userList();

    /**
     * 分页查询
     *
     * @return
     */
    @Select("SELECT * FROM mayikt_user limit 0,2")
    List<MayiktUser> userListPage();

    /**
     * 排序
     *
     * @return
     */
    @Select("SELECT * FROM mayikt_user order by id desc ")
    List<MayiktUser> userOrderBy();

    /**
     * get by id
     *
     * @return
     */
    @Select("SELECT * FROM mayikt_user where id =#{id} ")
    List<MayiktUser> getByUserId(Long id);
}



Controller:

package com.taotao.shardingjdbc.controller;

import com.taotao.shardingjdbc.entity.MayiktUser;
import com.taotao.shardingjdbc.mapper.MayiktUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 *@author tom
 *Date  2020/11/6 0006 8:41
 *
 */
@RestController
public class UserController {
    @Autowired
    private MayiktUserMapper mayiktUserMapper;


    @RequestMapping("/insertUser")
    public  String insertUser(){
        for (int i = 0; i <10 ; i++) {
            MayiktUser mayiktUser=new MayiktUser(i,"mykt"+i,i);
           try {
                mayiktUserMapper.insert(mayiktUser);
           }catch (Exception e){
               e.printStackTrace();
           }
        }
             return  "success";
    }

/**
 * 查询所有
 */

@RequestMapping("/userList")
public List<MayiktUser> userList(){
    return  mayiktUserMapper.userList();
}

/**
 * 分页查询
 */
@RequestMapping("/userListPage")
public  List<MayiktUser> userListpage(){
    return  mayiktUserMapper.userListPage();
}
/**
 * 排序
 */

@RequestMapping("/userOrderBy")
    public  List<MayiktUser> userOrderBy(){
    return  mayiktUserMapper.userOrderBy();
}

@RequestMapping("/getByUserId")
    public  List<MayiktUser> getByUserId(Long id){
    return  mayiktUserMapper.getByUserId(id);
}
}






package com.taotao.rfspringboot.config;

import io.shardingsphere.api.algorithm.sharding.PreciseShardingValue;
import io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm;

import java.util.Collection;

/**
 * 数据库分片规则
 *
 * @author Mos
 */
public class DataBasePreciseRule  implements PreciseShardingAlgorithm<Long> {


  @Override
  public String doSharding(Collection<String> databaseNames, PreciseShardingValue<Long> shardingValue) {

    /**
     * databaseNames 所有分片库的集合
     * shardingValue 为分片属性,其中 logicTableName 为逻辑表,columnName 分片健(字段),value 为从 SQL 中解析出的分片健的值
     */
    for (String databaseName : databaseNames) {

      String value = shardingValue.getValue() % databaseNames.size()+1 + "";
      if (databaseName.endsWith(value)) {
        System.out.println(databaseName+"&&&"+shardingValue.getValue() +"*********"+databaseNames.size());
        return databaseName;
      }
    }
    throw new IllegalArgumentException();


  }
}

package com.taotao.rfspringboot.config;

import io.shardingsphere.api.algorithm.sharding.PreciseShardingValue;
import io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
import lombok.extern.slf4j.Slf4j;

import java.util.Collection;

@Slf4j
public class MayiktRangeShardingAlgorithm implements PreciseShardingAlgorithm<Long> {


    @Override
    public String doSharding(Collection<String> databaseNames, PreciseShardingValue<Long> shardingValue) {

        /**
         * databaseNames 所有分片库的集合
         * shardingValue 为分片属性,其中 logicTableName 为逻辑表,columnName 分片健(字段),value 为从 SQL 中解析出的分片健的值
         */
      for (String databaseName : databaseNames) {
            String value = shardingValue.getValue() % databaseNames.size() + "";
            if (databaseName.endsWith(value)) {
                return databaseName;
            }
        }
        throw new IllegalArgumentException();


    }



}

归并数据原理

1.SELECT * FROM mayikt_user
底层发出多条语句查询每张表数据,在本地实现数据合并

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