一、如何进行分库分表

1、概念:

将原本存储在单个数据库上的数据拆分到多个数据库中(分库),把原来存储在单张表的数据拆分到多张数据表中,实现数据切分,从而提生数据库操作性能。分库分表的实现方式分为两种:垂直切分,水平切分。

2、水平拆分:

将数据分散到多张表,涉及到分区键。

  • 分库:每个库结构一样,数据不一样,没有交集。库多了可以缓解io和cpu压力。
  • 分表:每个表结构一样,数据不一样,没有交集。表数量减少,可以提高sql执行效率,减轻cpu压力。

优缺点:

  • 优点:
    • 单库(表)的数据保持在一定的量(减少),有助于性能的提高。
    • 拆分结构相同,程序改造较小
  • 缺点:
    • 数据扩容有难度,维护量大。
    • 拆分规则很难抽象出来
    • 分片事务的一致性的问题,部分业务无法关联。
3、垂直拆分:

将字段拆分为多张表,需要一定的重构。

  • 分库:每个库结构,数据都不一样,所有库的并集为全量数据。
  • 分表:每个表结构、数据不一样,至少有一列交集,用于关联数据,所有表的并集为全量数据。

优缺点:

  • 优点:
    • 拆分后业务清晰(专库专用按业务拆分)
    • 数据维护简单、按业务不同放到不同机器上。
  • 缺点:
    • 单表数据量大,写和读的压力大
    • 受某种业务来决定或者被限制。也就是说一个业务往往会影响到数据库的瓶颈(性能问题)。

二、分库分表开源框架

1、jdbc直连层

shardingshpere、tddl(淘宝)

  • 优点:快速性能高、支持跨数据库

  • 缺点:不支持跨语言。

2、proxy代理层

mycat、mysql-proxy

  • 优点:需要网络、支持跨平台、跨语言

  • 缺点:性能比jdbc低、不支持跨数据库

三、分库分表存在的问题

1、分布式事务

ACID(原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性)

当我们在进行多个数据库CURD(增删改查)操作的时候,如果出现错误,那么事务在回滚时只支持一个数据库的回滚,而其他数据库则是会操作成功,那么就会出现脏数据的出现。数据一致性不会得到保证

2、分布式id

在分表中存在,自增id会存在id重复的情况。

3、分布式查询 join

join查询存在数据组合问题。

4、多数据库源管理

四、springboot整合shareingshere

1、导入依赖
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.1.1</version>
</dependency>
2、配置
spring:
  shardingsphere:
    datasource:
      names: master,slave
      commoun:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/shop?serverTimezone=UTC&characterEncoding=utf8&useUnicode=tr&ueuseSSL=false
        username: root
        password: root
        hikari:
          # 连接池最小空闲连接数
          minimum-idle: 5
          # 连接池允许的最大连接数
          maximum-pool-size: 10
          # 等待连接池分配连接的最大时长(毫秒)
          connection-timeout: 30000
      master:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/shop?serverTimezone=UTC&characterEncoding=utf8&useUnicode=tr&ueuseSSL=false
        username: root
        password: root
      slave:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/shop?serverTimezone=UTC&characterEncoding=utf8&useUnicode=tr&ueuseSSL=false
        username: root
        password: root
    props:
      sql:
        show: true
mybatis:
  configuration:
    # 数据库下划线转驼峰配置
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:/mybatis/mapper/*.xml
3、分片配置
 sharding:
      tables:
        employee:
          actualDataNodes: master.employee_$->{0..2}
          tableStrategy:
            inline:
              shardingColumn: id
              algorithmExpression: employee_$->{id % 2}
          keyGenerator:
            type: SNOWFLAKE
            column: id
          #进行分库配置 按照id进行分库
      binding-tables: employee
#          databaseStrategy:
#            inline:
#              shardingColumn: id
#              algorithmExpression: employee_$->{id % 2}
4、读写分离与分片整合配置
    sharding:
      binding-tables: employee
      tables:
        employee:
          actualDataNodes: ms.employee_$->{0..2}
          tableStrategy:
            inline:
              shardingColumn: d_id
              algorithmExpression: employee_$->{d_id % 2}
          keyGenerator:
            type: SNOWFLAKE
            column: d_id
      default-table-strategy:
        none:
      default-key-generator:
        type: SNOWFLAKE
        column: d_id
      default-data-source-name: master
      master-slave-rules:
        ms:
          slave-data-source-names: slave
          load-balance-algorithm-type: round_robin
          master-data-source-name: master

五、测试

1、测试查询
@GetMapping("select")
public List<Employee> insertDept(Employee employee) {
    return employeeMapper.getEmp(employee);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zZmpyAfw-1642644484182)(E:\Typora文件存储\image\image-20211228160421572.png)]

  • 查询所有:
<select id="getEmp" resultType="com.beans.Employee">
    select *
    from employee
</select>
  • 查询在slave中进行查询

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tYn4Tq6W-1642644484183)(E:\Typora文件存储\image\image-20211228160254893.png)]

2、测试插入
@GetMapping("insert")
public Long insert(Employee employee) {
    employee.setDId(12L);
    employee.setGender(1);
    employee.setDate(new Date());
    employee.setEmail("123121312@12312");
    employeeMapper.insertEmp(employee);
    return employee.getId();
}
  • 插入一条数据
<insert id="insertEmp" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO employee(lastName, email, gender, d_id, date)
    VALUES (#{lastName}, #{email}, #{gender}, #{dId}, #{date})
</insert>
  • 插入会在master进行
    在这里插入图片描述
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐