当公司业务量上去之后,单表支撑不了的时候,分库分表就是一个绕不开的话题,小弟最近新入职一家公司,发现这边公司在用ShardingSphere来进行分库分表,之前没接触过这方面,所以就写了个demo学习一下,下面文章就记录一下如何用ShardingSphere来进行分库分表!(能力有限,本章不会讲原理奥,只是记录如何分库分表,原理方面后面我学习了再写,现在先会用先0.0,)
1、官网文档地址
这是ShardingSphere官网文档的地址,有需要的可以点进去看一下。
2、技术及环境
| 数据库 | 项目用到的技术 | 
|---|---|
| mysql5.6 | springboot、mybatis、shardingsphere | 
3、建库建表
1、新建两个数据库:一个user0,一个user1。
2、在user0数据库新建两个表:一个us_admin0,一个us_admin1,新建语句如下:
CREATE TABLE `us_admin0` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `user_id` int(11) NOT NULL COMMENT '用户id',
 `addr_id` int(11) NOT NULL COMMENT '地址id',
  `user_name` varchar(64) NOT NULL COMMENT '用户编号',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后台用户表';
CREATE TABLE `us_admin1` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `user_id` int(11) NOT NULL COMMENT '用户id',
 `addr_id` int(11) NOT NULL COMMENT '地址id',
  `user_name` varchar(64) NOT NULL COMMENT '用户编号',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后台用户表';
3、在user1数据库新建两个表:一个us_admin0,一个us_admin1,新建语句如下:
CREATE TABLE `us_admin0` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `user_id` int(11) NOT NULL COMMENT '用户id',
 `addr_id` int(11) NOT NULL COMMENT '地址id',
  `user_name` varchar(64) NOT NULL COMMENT '用户编号',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后台用户表';
CREATE TABLE `us_admin1` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `user_id` int(11) NOT NULL COMMENT '用户id',
 `addr_id` int(11) NOT NULL COMMENT '地址id',
  `user_name` varchar(64) NOT NULL COMMENT '用户编号',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后台用户表';
4、搭建springboot项目
这部分就idea自己创建一下就好了,pom文件及配置文件内容如下:
pom文件:
<?xml  version="1.0" encoding="UTF-8"?>
"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">4.0.0org.springframework.bootspring-boot-starter-parent2.0.7.RELEASE com.shardingsphere1.0.0-SNAPSHOTsphereDemo project for Spring Boot1.8Hoxton.SR33.8.28.0.12junitjunit4.12testorg.springframework.bootspring-boot-starter-web-servicesorg.springframework.bootspring-boot-starter-testtestorg.junit.vintagejunit-vintage-engineorg.apache.shardingspheresharding-jdbc-spring-boot-starter4.0.0-RC1com.alibabadruid-spring-boot-starter1.1.14mysqlmysql-connector-javaorg.springframework.bootspring-boot-starter-actuatororg.mybatis.spring.bootmybatis-spring-boot-starter2.1.2org.springframework.bootspring-boot-maven-plugin
application.yml配置:
# 服务端口
server:
  port: 8888
# 服务名
spring:
  application:
    name: test-user
  # 配置sharding jdbc分片规则
  shardingsphere:
    datasource:
      # 连接名称(下面要用这个名称来区分库)
      names: ds0,ds1
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.1.19:3306/user0?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: root
        password: 123
        initialSize: 5      #初始化大小
        maxActive: 200       #最大值
        maxWait: 2000      #最大等待时间,配置获取连接等待超时,时间单位都是毫秒ms
        timeBetweenEvictionRunsMillis: 60000    #配置间隔多久才进行一次检测,检测需要关闭的空闲连接
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.1.19:3306/user1?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: root
        password: 123
        initialSize: 5      #初始化大小
        maxActive: 200       #最大值
        maxWait: 2000      #最大等待时间,配置获取连接等待超时,时间单位都是毫秒ms
        timeBetweenEvictionRunsMillis: 60000    #配置间隔多久才进行一次检测,检测需要关闭的空闲连接
    # 配置分片规则
    sharding:
      # 按表来区分
      tables:
        us_admin:
          # 配置数据节点
          actualDataNodes: ds${0..1}.us_admin${0..1}
          # 分库策略
          databaseStrategy:
            inline:
              # 分库的规则 用user_id这个字段来分库 总共有两个库 及ds0(user0)与ds1(user1)
              shardingColumn: user_id
              algorithmExpression: ds${user_id % 2}
          # 分表策略
          tableStrategy:
            inline:
              shardingColumn: addr_id
              algorithmExpression: us_admin${addr_id % 2}
          keyGenerator:
            column: id
            type: SNOWFLAKE
      bindingTables:
        us_admin
      broadcastTables:
        t_config
      defaultDataSourceName: ds0
    props:
      sql.show: true
# 配置xml 的扫描路径
mybatis:
  mapper-locations: classpath:mapper/*.xml
  check-config-location: true
  type-aliases-package: com.sharding.sphere.model
  configuration:
    cacheEnabled: true
    mapUnderscoreToCamelCase: true
5、接口测试
编写增删改接口进行测试,分库根据user_id来切片,分表根据addr_id来切片,分别插入一些数据,结果如下:
@RestController
public class UserController {
    @Resource
    UserService userService;
    @RequestMapping("add")
    public Integer add(@RequestBody UsAdmin usAdmin){
        Integer add = userService.add(usAdmin);
        return add;
    }
    @RequestMapping("select")
    public List select(){
        List select = userService.select();return select;
    }@RequestMapping("delect")public Integer delect(Long id){
        Integer delect = userService.delect(id);return delect;
    }
}查询sql语句:
<select id="selectAll" resultMap="BaseResultMap">
    select
      id, addr_id, user_id, user_name
    from us_admin
  select>
新增sql语句:
<insert id="insertSelective" parameterType="com.sharding.sphere.model.UsAdmin">
    insert into us_admin
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      if>
      <if test="userId != null">
        user_id,
      if>
      <if test="addrId != null">
        addr_id,
      if>
      <if test="userName != null">
        user_name,
      if>
    trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=BIGINT},
      if>
      <if test="userId != null">
        #{userId,jdbcType=INTEGER},
      if>
      <if test="addrId != null">
        #{addrId,jdbcType=INTEGER},
      if>
      <if test="userName != null">
        #{userName,jdbcType=VARCHAR},
      if>
    trim>
  insert>
删除sql语句:
 delete from us_admin
    where id = #{id,jdbcType=BIGINT}
数据新增分表分库结果:

查询结果:

可以看到,新增数据的时候以user_id%2来计算分库,双数在user0库,单数在user1库,addr_id作为分表id,双数在us_admin0表,单数在us_admin1表,先确定库然后确定表,而查询一条语句可以查询到所有,不过ShardingSphere好像有些sql语句是不支持的,比如关联自己这种操作(us_admin left join us_admin这种),还有一些不支持的sql,具体的可以百度看看。
讲道理来看,ShardingSphere其实对代码的侵入量并不算多,只是有一些配置,配置好之后该写的sql跟原来一样的,可能是还没有踩到该踩的坑吧,等周末研究一下原理之后再写一篇文章分析分析。
6、公众号
如果你觉得我的文章对你有帮助话,欢迎关注我的微信公众号:"一个快乐又痛苦的程序员"(无广告,单纯分享原创文章、已pj的实用工具、各种Java学习资源,期待与你共同进步)