SpringBoot+Mybatis-Plus+ShardingSphere分库分表

5,611 阅读5分钟

ShardingSphere简介

ShardingSphere是由Apache开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(规划中)这3款相互独立,却又能够混合部署配合使用的产品组成。它们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如Java同构、异构语言、云原生等各种多样化的应用场景。

ShardingSphere定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。它通过关注不变,进而抓住事物本质。关系型数据库当今依然占有巨大市场,是各个公司核心业务的基石,未来也难于撼动,我们目前阶段更加关注在原有基础上的增量,而非颠覆。

1.Sharding-JDBC

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

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

2.Sharding-Proxy

定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前先提供MySQL/PostgreSQL版本,它可以使用任何兼容MySQL/PostgreSQL协议的访问客户端(如:MySQL Command Client, MySQL Workbench, Navicat等)操作数据,对DBA更加友好。

向应用程序完全透明,可直接当做MySQL/PostgreSQL使用。 适用于任何兼容MySQL/PostgreSQL协议的的客户端。

3.Sharding-Sidecar

定位为Kubernetes的云原生数据库代理,以Sidecar的形式代理所有对数据库的访问。 通过无中心、零侵入的方案提供与数据库交互的的啮合层,即Database Mesh,又可称数据网格。

Database Mesh的关注重点在于如何将分布式的数据访问应用与数据库有机串联起来,它更加关注的是交互,是将杂乱无章的应用与数据库之间的交互有效的梳理。使用Database Mesh,访问数据库的应用和数据库终将形成一个巨大的网格体系,应用和数据库只需在网格体系中对号入座即可,它们都是被啮合层所治理的对象。

数据库信息

地址1: 192.169.50.200

数据库名称1: ds0

ds0库表名:

user_info_0

user_info_1

user_info_2

地址2: 192.169.50.201

数据库名称: ds1

ds1库表名:

user_info_0

user_info_1

user_info_2

创建如下表结构,id一定不要使用自增,使用shardingsphere自带的SNOWFLAKE(雪花算法)

DROP TABLE IF EXISTS `user_info_0`;
CREATE TABLE `user_info_0` (
  `id` bigint(32) unsigned NOT NULL DEFAULT '0' COMMENT '主键',
  `name` varchar(64) CHARACTER SET utf8 DEFAULT NULL COMMENT '姓名',
  `sex` varchar(32) CHARACTER SET utf8 DEFAULT NULL COMMENT '性别',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `status` tinyint(1) DEFAULT NULL COMMENT '是否删除 1删除 0未删除',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

工程结构

1.pom.xml配置

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>sharding</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.1</version>
        </dependency>
        <!--shardingsphere-->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-namespace</artifactId>
            <version>4.0.0-RC2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.20</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.mongo.ShardingApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.application.yml配置详解

server:
  port: 8081

spring:
  shardingsphere:
    props:
      sql:
        #设置sql是否展示
        show: true
    datasource:
      #数据库名称(可以与数据库中的库名不一致)
      names: ds0,ds1
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.169.50.200:3306/ds0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
        username: root
        password: ROOT
        # 数据库连接池的最小连接数
        min-idle: 5
        # 初始化连接数
        initial-size: 5
        # 最大连接数
        max-total: 5
        max-wait-millis: 200s
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.169.50.201:3306/ds1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
        username: root
        password: ROOT
        # 数据库连接池的最小连接数
        min-idle: 5
        # 初始化连接数
        initial-size: 5
        # 最大连接数
        max-total: 5
        max-wait-millis: 200s
    sharding:
      #分库策略
      default-database-strategy:
        inline:
          #根据id取模决定去那个库
          algorithm-expression: ds$->{id % 2}
          sharding-column: id
      tables:
        #逻辑表名,这里的user_info为逻辑表名,user_info_0,user_info_1,user_info_2为实际表
        user_info:
          actual-data-nodes: ds$->{0..1}.user_info_$->{0..2}
          table-strategy:
            #根据id取模决定去那个表
            inline:
              sharding-column: id
              algorithm-expression: user_info_$->{id % 3}
          key-generator:
            #id使用雪花算法
            column: id
            #雪花算法
            type: SNOWFLAKE

3.Mybatis-Plus配置

package com.mongo.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @ClassName MybatisPlusConfig
 * @Description Mybatis-Plus配置
 * @Author Z咸鱼有梦
 * @Date 2019/12/02 0025 15:28
 * @Version 1.0
 */
@Configuration
public class MybatisPlusConfig {
    /**
     * 分页插件
     * @return
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

    /**
     * 乐观锁插件
     * @return
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

    /**
     * sql执行效率插件
     * @return
     */
   @Bean
   public PerformanceInterceptor performanceInterceptor() {
       return new PerformanceInterceptor();
   }
}

4.实体类UserInfo

package com.mongo.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDate;

/**
 * @ClassName UserInfo
 * @Description 用户信息
 * @Author Z咸鱼有梦
 * @Date 2019/12/02 0025 15:28
 * @Version 1.0
 */
@Data
@TableName(value = "user_info")
public class UserInfo {
    private Long id;
    private String name;
    private String sex;
    private Integer age;
    private LocalDate createTime;
    private LocalDate updateTime;
    private Short status;
}

5.实体类UserInfoVo

package com.mongo.vo;

import lombok.Data;
import java.time.LocalDate;

/**
 * @ClassName UserInfoVo
 * @Description 用户信息VO
 * @Author Z咸鱼有梦
 * @Date 2019/12/02 0025 15:28
 * @Version 1.0
 */
@Data
public class UserInfoVo {
    private String name;
    private String sex;
    private Integer age;
    private LocalDate createTime;
    private LocalDate updateTime;
    private Short status;
}

6.Mapper接口UserInfoMapper

package com.mongo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mongo.entity.UserInfo;

/**
 * @ClassName UserInfoMapper
 * @Description UserInfo ORM
 * @Author Z咸鱼有梦
 * @Date 2019/12/02 0025 15:28
 * @Version 1.0
 */
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}

7.Service接口UserInfoService

package com.mongo.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.mongo.entity.UserInfo;

/**
 * @ClassName UserInfoService
 * @Description UserInfo业务逻辑接口
 * @Author Z咸鱼有梦
 * @Date 2019/12/02 0025 15:28
 * @Version 1.0
 */

public interface UserInfoService extends IService<UserInfo>{
}

8.Service实现类UserInfoServiceImpl

package com.mongo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mongo.entity.UserInfo;
import com.mongo.mapper.UserInfoMapper;
import com.mongo.service.UserInfoService;
import org.springframework.stereotype.Service;

/**
 * @ClassName UserInfoServiceImpl
 * @Description UserInfo业务逻辑实现类
 * @Author Z咸鱼有梦
 * @Date 2019/12/02 0025 15:28
 * @Version 1.0
 */

@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>  implements UserInfoService {
}

9.Controller类UserInfoController

package com.mongo.controller;

import com.mongo.entity.UserInfo;
import com.mongo.service.UserInfoService;
import com.mongo.vo.UserInfoVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @ClassName UserInfoController
 * @Description UserInfo接口请求层
 * @Author Z咸鱼有梦
 * @Date 2019/12/02 0025 15:28
 * @Version 1.0
 */
@RestController
@RequestMapping("/api/v1/user")
public class UserInfoController {

    @Autowired
    private UserInfoService userInfoService;

    /**
     * 保存用户信息
     * @return
     */
    @PostMapping("/saveUser")
    public String saveUser(@RequestBody UserInfoVo userInfoVo){
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(userInfoVo,userInfo);
        userInfoService.save(userInfo);
      return "SUCCESS";
    }
}

9.应用程序启动类

package com.mongo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @ClassName ShardingApplication
 * @Description 应用程序启动类
 * @Author Z咸鱼有梦
 * @Date 2019/12/02 0025 15:28
 * @Version 1.0
 */
@SpringBootApplication
@MapperScan(basePackages = {"com.mongo.mapper"})
public class ShardingApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShardingApplication.class,args);
    }
}

PostMan接口测试

url地址

127.0.0.1:8081/api/v1/user/saveUser

Json串

{ "name":"李四", "sex":"男", "age":20, "createTime":"2019-12-01", "updateTime":"2019-12-02", "status":1 }

数据分布

gitee地址:

gitee.com/lgybean/mon…