超级简单分库分表实现方案+面试题和答案

152 阅读2分钟

分库分表:分为数据水平拆分字段垂直拆分,这边只做了一个简单 user 表数据水平拆分

实现方案:spring boot、mybatis、sharding-jdbc、mysql

mysql 创建库和表

-- 创建名为 user 的数据库 
CREATE DATABASE IF NOT EXISTS user DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

USE user;

-- 创建 user_0 表
CREATE TABLE IF NOT EXISTS user_0 (
    id INT PRIMARY KEY,
    name VARCHAR(255),
    age INT
);

-- 创建名为 order 的数据库 
CREATE DATABASE IF NOT EXISTS order DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

USE order;

-- 创建 user_1 表
CREATE TABLE IF NOT EXISTS user_1 (
    id INT PRIMARY KEY,
    name VARCHAR(255),
    age INT
);

依赖

<dependencies>
    <!-- MyBatis Starter -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.4</version>
    </dependency>

    <!-- MySQL Connector -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <!-- Sharding-JDBC -->
    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
        <version>5.0.0-alpha</version>
    </dependency>
</dependencies>

配置

spring:
  shardingsphere:
    datasource:
      #定义了数据源的名称
      names: ds0,ds1
      ds0:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/user?serverTimezone=UTC&useSSL=false
        username: root
        password: password
      ds1:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/order?serverTimezone=UTC&useSSL=false
        username: root
        password: password
    sharding:
      tables:
        user:
          #定义了实际数据节点,用于表示数据分片的数据源范围和表范围
          actual-data-nodes: ds${0..1}.user_${0..1}
          #定义了分表策略,这里使用了 inline 策略,根据id列进行分片
          table-strategy:
            inline:
              sharding-column: id
              algorithm-expression: user_$->{id % 2}
          #主键策略
          key-generator:
            #主键列为id
            column: id
            #主键通过雪花算法生成
            type: SNOWFLAKE

实体类

public class User {
    private Long id;
    private String name;
    private Integer age;
}

mapper

@Mapper
public interface UserMapper {
    @Select("SELECT * FROM user WHERE id = #{id}")
    User findById(Long id);

    @Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(User user);
}

面试题和答案

解决问题:
    单表数据量过大(业界标准超过500万条记录就要分,最大可存储2^23-1条数据)
    高并发访问压力:通过分库可以将请求分散到多个数据库中,降低单台数据库的压力

引发的问题:   
    分布式事务:可以用 2PC(AT、TCC、SAGA、XA) 的方式去解决分布式事务问题
    数据迁移:可以用阿里云的DTS、或者通过程序代码实现数据迁移到另一个库

可以实现的功能:
    主从复制:`主服务器` 复制数据到 `从服务器`
    读写分离:主数据库(写入)、从数据库(读取)