暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

sharding-jdbc初步学习

读读书写写代码 2021-09-26
351

背景

近期学习sharding-sphere,在网上找资料做实验,发现大部分都不全,对于预期结果没有足够的例子,大部分都是降了插入和查询操作。自己把例子抄了一遍,做了一遍实验,把实验结果记录了一下。代码就不贴了,需要的话留言。

数据准备

用docker作为测试数据库,使用如下的脚本来创建docker镜像.

 #compose.yaml
 #版本号
 version: "3"
 services:
 #第一个实例
  sharding_0:
    image: mysql
    restart: always
    hostname: sharding_0
    container_name: sharding_0
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: sharding
      TZ: Asia/Shanghai
    volumes:
      - ./sharding_0/mysql/data:/var/lib/mysql
      - ./sharding_0/mysql/log:/var/log/mysql
      - ./init-script_0:/docker-entrypoint-initdb.d/
  sharding_1:
    image: mysql
    restart: always
    hostname: sharding_1
    container_name: sharding_1
    ports:
      - 3316:3306
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: sharding
      TZ: Asia/Shanghai
    volumes:
      - ./sharding_1/mysql/data:/var/lib/mysql
      - ./sharding_1/mysql/log:/var/log/mysql
      - ./init-script_1:/docker-entrypoint-initdb.d/

按照配置中的要求创建相关目录,使用docker-compose up -d
来启动容器,其中,init-script_0
init-script_1
下面要事先放好如下的初始化脚本文件init.sql
,文件名随意。mysql官方镜像会使用/docker-entrypoint-initdb.d
下的sql来进行数据库初始化操作。

 # init.sql
 grant all PRIVILEGES on *.* to 'root'@'%' with grant option;
 flush privileges;
 use sharding;
 CREATE TABLE `t_user_0` (
   `id` BIGINT NOT NULL,
   `user_id` BIGINT NOT NULL,
   `user_name` varchar(128) NOT NULL,
   `user_nicky` varchar(128) NOT NULL,
   `user_mobile` varchar(32) NOT NULL,
   `user_status` char(1) NOT NULL DEFAULT '0',
   `user_level` char(2) NOT NULL DEFAULT '01',
   `user_point` INT NOT NULL DEFAULT '0',
   PRIMARY KEY (`id`),
   UNIQUE INDEX `unq_user0_user_id` (`user_id` ASC) VISIBLE,
   UNIQUE INDEX `unq_user0_user_name` (`user_name` ASC) VISIBLE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户信息表';
 
 CREATE TABLE `t_user_1` (
   `id` BIGINT NOT NULL,
   `user_id` BIGINT NOT NULL,
   `user_name` varchar(128) NOT NULL,
   `user_nicky` varchar(128) NOT NULL,
   `user_mobile` varchar(32) NOT NULL,
   `user_status` char(1) NOT NULL DEFAULT '0',
   `user_level` char(2) NOT NULL DEFAULT '01',
   `user_point` INT NOT NULL DEFAULT '0',
   PRIMARY KEY (`id`),
   UNIQUE INDEX `unq_user1_user_id` (`user_id` ASC) VISIBLE,
   UNIQUE INDEX `unq_user1_user_name` (`user_name` ASC) VISIBLE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户信息表';
 
 CREATE TABLE `sharding`.`t_order_0` (
   `id` BIGINT NOT NULL,
   `order_id` BIGINT NOT NULL,
   `order_user` BIGINT NOT NULL,
   `order_amount` SMALLINT NOT NULL,
   `order_address` VARCHAR(512) NOT NULL,
   `order_mobile` VARCHAR(32) NOT NULL,
   `order_memo` VARCHAR(256) NOT NULL,
   `order_status` CHAR(2) NOT NULL,
   PRIMARY KEY (`id`),
   UNIQUE INDEX `unq_order0_order_id` (`order_id` ASC) VISIBLE
   );
 
 CREATE TABLE `sharding`.`t_order_1` (
   `id` BIGINT NOT NULL,
   `order_id` BIGINT NOT NULL,
   `order_user` BIGINT NOT NULL,
   `order_amount` SMALLINT NOT NULL,
   `order_address` VARCHAR(512) NOT NULL,
   `order_mobile` VARCHAR(32) NOT NULL,
   `order_memo` VARCHAR(256) NOT NULL,
   `order_status` CHAR(2) NOT NULL,
   PRIMARY KEY (`id`),
   UNIQUE INDEX `unq_order0_order_id` (`order_id` ASC) VISIBLE
   );
 
 CREATE TABLE `sharding`.`t_goods` (
   `id` BIGINT NOT NULL,
   `goods_id` BIGINT NOT NULL,
   `goods_name` varchar(256) NOT NULL,
   `goods_type` TINYINT NOT NULL,
   `goods_price` SMALLINT NOT NULL,
   `goods_desp` VARCHAR(32) NOT NULL,
   `goods_tags` VARCHAR(256) NOT NULL,
   `goods_picture` VARCHAR(256) NOT NULL,
   `goods_status` CHAR(2) NOT NULL,
   PRIMARY KEY (`id`),
   UNIQUE INDEX `unq_goods_goods_id` (`goods_id` ASC) VISIBLE
   );
 

试验

使用springboot、mybatis、sharding-jdbc作为主要的试验环境,其中最关键的分库分表配置如下所示:

 #application.yml
 server:
  port: 8081
 
 mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.study.cn.entity
 
 #配置数据源
 spring:
  main:
    allow-bean-definition-overriding: true
  shardingsphere:
    datasource:
      names: ds1,ds0 # 数据源名称
      ds1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:3306/sharding?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:3316/sharding?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
    sharding:
      default-data-source-name: ds0
      default-database-strategy:
        inline:
          sharding-column: id
          algorithm-expression: ds$->{id % 2}
         #binding-tables: t_user
      tables:
        t_user:
          actual-data-nodes: ds$->{0..1}.t_user_$->{0..1}
          table-strategy:
            inline:
              sharding-column: user_id
              algorithm-expression: t_user_$->{user_id % 2}
          key-generator:
            column: id
            type: SNOWFLAKE
            props:
              worker:
                id: 10
        t_order:
          actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
          table-strategy:
            inline:
              sharding-column: order_id
              algorithm-expression: t_order_$->{order_id % 2}
          key-generator:
            column: id
            type: SNOWFLAKE
            props:
              worker:
                id: 20
        t_goods:
          actual-data-nodes: ds$->{0..1}.t_goods
          database-strategy:
            inline:
              sharding-column: id
              algorithm-expression: ds$->{id % 2}
          key-generator:
            column: id
            type: SNOWFLAKE
          props:
            worker:
 #             id: 30
    props:
      sql:
        show: true

整体参考了shardingsphere的官方例子:https://github.com/apache/shardingsphere-example

这种模式下,sharding-jdbc就像一个增强版的JDBC,应用程序操作逻辑表,t_user,t_order,t_goods,转换到实际的数据库操作时,sharding-jdbc会转换为具体的数据库操作,可能是ds0.t_user_0,ds1.t_user_1等等,完成了实际的分库分表。有几点需要注意:

  • 查询模式下,查询结果是几个查询结果的并集;

  • 如果要精确查询,分库和分表的字段都要在sql的where条件下,根据两个条件确定actual-data-node
    ,然后发起查询;

  • 更新模式下,和查询类似,如果条件中没有包含所有的分库分表条件,则会根据实际条件情况分别执行。比如如果没有指定分库条件,则会在两个ds上执行,如果指定了分表条件,则在每个ds中路由到具体的分表执行;

这种模式下,使用jpa则问题多多,jpa的save方法,默认使用id作为条件,会提示“分表字段不能更新“之类的错误,使用mybatis精准控制sql更加方便。

当然,jpa可能有高级用法,目前还没有学习到。


文章转载自读读书写写代码,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论