Java猿社区—ShardingSphere4.0.0-RC1实现分库分表+读写分离

转自:https://zhouzhixiang.blog.csdn.net/article/details/104853953  感谢作者的分享

文章目录


参考:
基于Docker的Mysql主从复制搭建
ShardingSphere官网

 

技术体系

Springboot2.1.5 + shardingsphere4.0.0-RC1 + Mysql5.7 + mysql-connector-java5.1.47
  • 1

背景

目前公司正在进行的在线客服IM项目,考虑未来会话消息请求流量剧增以及消息存储带来的挑战,单一数据库无法支撑,需要分库&分表、读写分离以应对高并发带来的挑战。
基于市面上较为流行的几个数据库中间件我们结合公司技术体系,再三考虑,决定使用ShardingSphere作为在线客服项目的数据库中间件。

ShardingSphere介绍

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

ShardingShpere支持的功能

数据分片

  • 分库、分表
  • 读写分离
  • 分片策略定制化
  • 无中心化分布式主键

分布式事务

  • 标准化事务接口
  • XA强一致事务
  • 柔性事务

技术准备

mysql安装配置

具体安装配置请参见网络博客:如基于Docker的Mysql主从复制搭建

POM配置

<?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>com.zzx.shardingsphere</groupId>
    <artifactId>zzx-shardingsphere</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <modules>
        <module>db-read-write</module>
        <module>db-table-read-write</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <java.version>1.8</java.version>
        <mybatis-spring-boot>2.0.1</mybatis-spring-boot>
        <druid>1.1.16</druid>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <shardingsphere.version>4.0.0-RC1</shardingsphere.version>
        <fastjson.version>1.2.38</fastjson.version>
        <mysql-connector-java.version>5.1.47</mysql-connector-java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis-spring-boot}</version>
        </dependency>
        <!--mybatis驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connector-java.version}</version>
        </dependency>
        <!--druid数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid}</version>
        </dependency>
        <!--shardingsphere版本-->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>${shardingsphere.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-namespace</artifactId>
            <version>${shardingsphere.version}</version>
        </dependency>
        <!--lombok实体工具-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
  •  

分库分表+读写分离

mysql配置环境

主库0: localhost:3342/im_bis
主库0->从库0: localhost:3343/im_bis
主库1: localhost:3344/im_bis
主库1->从库1: localhost:3345/im_bis

配置从库0和从库1分别作为主库0和主库1的从库,具体配置参考上面提到的基于Docker搭建主从复制网站

sql脚本


/*
 Navicat Premium Data Transfer

 Source Server         : 192.168.89.53
 Source Server Type    : MySQL
 Source Server Version : 50726
 Source Host           : 192.168.89.53:3306
 Source Schema         : ddky_im_bis

 Target Server Type    : MySQL
 Target Server Version : 50726
 File Encoding         : 65001

 Date: 08/03/2020 13:18:39
*/

DROP SCHEMA IF EXISTS im_bis;
CREATE SCHEMA IF NOT EXISTS im_bis;
use im_bis

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for im_team_message
-- ----------------------------
DROP TABLE IF EXISTS `im_team_message0`;
CREATE TABLE `im_team_message0` (
  `id` bigint(20) NOT NULL COMMENT '主键id',
  `team_msg_id` bigint(20) DEFAULT NULL COMMENT '群消息id(服务端生成消息id)',
  `team_client_msg_id` varchar(32) DEFAULT '' COMMENT '群消息id(客户端生成)',
  `team_id` bigint(20) DEFAULT NULL COMMENT '群组id(对应群组的accid)',
  `msg_type` varchar(15) DEFAULT 'TEXT' COMMENT '消息类型:TEXT-文本,PICTURE-图片,AUDIO-音频,VIDEO-视频,FILE-文件,GEO-地理位置,CUSTOM-自定义,TIP-提醒,ROBOT-AI机器人,NOTICATION-群通知,TEAM_INVITE-邀请入群,TEAM_INVITE_REJECT-拒绝邀请,CUSTOM_TEAM_MSG -群组自定义系统通知',
  `event_type` tinyint(4) DEFAULT '1' COMMENT '事件类型:1-会话类型消息(p2p消息、群聊消息、自定义系统通知、云信内置系统通知),2-登录事件,3-登出/离线事件,4-聊天室聊天消息,5-音视频时长、白板时长消息,6-音视频白板大小、下载地址消息,7-单聊消息撤回,8-群聊消息撤回,9-汇报主播、管理员进出聊天室事件消息,10-汇报专线电话通话结束回调抄送的消息,11-汇报短信回执抄送的消息,12-汇报短信上行消息,13-汇报用户进出音视频/白板房间的消息,14-汇报聊天室队列操作的事件消息,20-易盾异步反垃圾结果信息',
  `remind_type` tinyint(4) DEFAULT '0' COMMENT '提醒类型:0-普通消息,1-客服进入,2-客户进入,3-客服进入欢迎提醒,4-敏感词命中提醒消息',
  `conv_type` varchar(20) DEFAULT '' COMMENT '场景类型:TEAM',
  `scene` tinyint(4) DEFAULT '0' COMMENT '场景:0-team,1-p2p,2-superTeam',
  `text` varchar(5000) DEFAULT '' COMMENT '内容',
  `attach` varchar(5000) DEFAULT '' COMMENT '附加消息',
  `team_attach_type` tinyint(4) DEFAULT NULL COMMENT '群通知类型:默认null(普通消息),0-更新群,1-拉人入群,2-踢人出群,3-接受入群邀请,4-通过入群邀请,5-添加群管理员,6-移除群管理员,7-主动退群,8-解散群,9-转让群,10-更新群成员禁言状态',
  `send_type` tinyint(4) DEFAULT '0' COMMENT '发送人类型:0-用户,1-客服,2-药师,3-医生',
  `send_client_ip` varchar(20) DEFAULT '' COMMENT '发送端ip',
  `send_client_port` varchar(5) DEFAULT '' COMMENT '发送端端口',
  `send_client_type` varchar(10) DEFAULT '' COMMENT '发送客户端类型: AOS、IOS、PC、WINPHONE、WEB、REST',
  `send_device_id` varchar(32) DEFAULT '' COMMENT '发送端设备编号',
  `send_nick` varchar(50) DEFAULT '' COMMENT '发送人昵称',
  `send_id` varchar(32) DEFAULT '' COMMENT '发送人id(对应客服表和用户表的accid)',
  `send_at` bigint(11) DEFAULT NULL COMMENT '发送时间',
  `msg_receipt_time` bigint(11) DEFAULT NULL COMMENT '已读回执时间戳,如果有此字段, 说明此时间戳之前的所有消息对方均已读',
  `is_revoke` tinyint(4) DEFAULT '0' COMMENT '是否撤销:0-否,1-是',
  `revoke_at` bigint(11) DEFAULT '0' COMMENT '撤销时间',
  `custom_apns_text` varchar(200) DEFAULT '' COMMENT '自定义系统通知消息推送文本。仅在convType为CUSTOM_PERSON或CUSTOM_TEAM时含此字段',
  `ext` varchar(64) DEFAULT '' COMMENT '消息扩展字段',
  `antispam` varchar(12) DEFAULT '' COMMENT '标识是否被反垃圾(‘’,true,false)',
  `yidun_res` varchar(500) DEFAULT '' COMMENT '易盾反垃圾的原始处理细节',
  `msg_status` tinyint(4) DEFAULT '0' COMMENT '消息发送状态:0-发送成功,1-发送中,2-发送失败',
  `status` tinyint(4) DEFAULT '0' COMMENT '状态:有效 0:无效',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_tt` (`id`,`team_msg_id`,`team_client_msg_id`) USING BTREE,
  KEY `index_team_id_on_im_team_message` (`team_id`),
  KEY `index_send_at_on_im_team_message` (`send_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IM消息表';

SET FOREIGN_KEY_CHECKS = 1;


/*
 Navicat Premium Data Transfer

 Source Server         : 192.168.89.53
 Source Server Type    : MySQL
 Source Server Version : 50726
 Source Host           : 192.168.89.53:3306
 Source Schema         : ddky_im_bis

 Target Server Type    : MySQL
 Target Server Version : 50726
 File Encoding         : 65001

 Date: 08/03/2020 13:18:39
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for im_team_message
-- ----------------------------
DROP TABLE IF EXISTS `im_team_message1`;
CREATE TABLE `im_team_message1` (
  `id` bigint(20) NOT NULL COMMENT '主键id',
  `team_msg_id` bigint(20) DEFAULT NULL COMMENT '群消息id(服务端生成消息id)',
  `team_client_msg_id` varchar(32) DEFAULT '' COMMENT '群消息id(客户端生成)',
  `team_id` bigint(20) DEFAULT NULL COMMENT '群组id(对应群组的accid)',
  `msg_type` varchar(15) DEFAULT 'TEXT' COMMENT '消息类型:TEXT-文本,PICTURE-图片,AUDIO-音频,VIDEO-视频,FILE-文件,GEO-地理位置,CUSTOM-自定义,TIP-提醒,ROBOT-AI机器人,NOTICATION-群通知,TEAM_INVITE-邀请入群,TEAM_INVITE_REJECT-拒绝邀请,CUSTOM_TEAM_MSG -群组自定义系统通知',
  `event_type` tinyint(4) DEFAULT '1' COMMENT '事件类型:1-会话类型消息(p2p消息、群聊消息、自定义系统通知、云信内置系统通知),2-登录事件,3-登出/离线事件,4-聊天室聊天消息,5-音视频时长、白板时长消息,6-音视频白板大小、下载地址消息,7-单聊消息撤回,8-群聊消息撤回,9-汇报主播、管理员进出聊天室事件消息,10-汇报专线电话通话结束回调抄送的消息,11-汇报短信回执抄送的消息,12-汇报短信上行消息,13-汇报用户进出音视频/白板房间的消息,14-汇报聊天室队列操作的事件消息,20-易盾异步反垃圾结果信息',
  `remind_type` tinyint(4) DEFAULT '0' COMMENT '提醒类型:0-普通消息,1-客服进入,2-客户进入,3-客服进入欢迎提醒,4-敏感词命中提醒消息',
  `conv_type` varchar(20) DEFAULT '' COMMENT '场景类型:TEAM',
  `scene` tinyint(4) DEFAULT '0' COMMENT '场景:0-team,1-p2p,2-superTeam',
  `text` varchar(5000) DEFAULT '' COMMENT '内容',
  `attach` varchar(5000) DEFAULT '' COMMENT '附加消息',
  `team_attach_type` tinyint(4) DEFAULT NULL COMMENT '群通知类型:默认null(普通消息),0-更新群,1-拉人入群,2-踢人出群,3-接受入群邀请,4-通过入群邀请,5-添加群管理员,6-移除群管理员,7-主动退群,8-解散群,9-转让群,10-更新群成员禁言状态',
  `send_type` tinyint(4) DEFAULT '0' COMMENT '发送人类型:0-用户,1-客服,2-药师,3-医生',
  `send_client_ip` varchar(20) DEFAULT '' COMMENT '发送端ip',
  `send_client_port` varchar(5) DEFAULT '' COMMENT '发送端端口',
  `send_client_type` varchar(10) DEFAULT '' COMMENT '发送客户端类型: AOS、IOS、PC、WINPHONE、WEB、REST',
  `send_device_id` varchar(32) DEFAULT '' COMMENT '发送端设备编号',
  `send_nick` varchar(50) DEFAULT '' COMMENT '发送人昵称',
  `send_id` varchar(32) DEFAULT '' COMMENT '发送人id(对应客服表和用户表的accid)',
  `send_at` bigint(11) DEFAULT NULL COMMENT '发送时间',
  `msg_receipt_time` bigint(11) DEFAULT NULL COMMENT '已读回执时间戳,如果有此字段, 说明此时间戳之前的所有消息对方均已读',
  `is_revoke` tinyint(4) DEFAULT '0' COMMENT '是否撤销:0-否,1-是',
  `revoke_at` bigint(11) DEFAULT '0' COMMENT '撤销时间',
  `custom_apns_text` varchar(200) DEFAULT '' COMMENT '自定义系统通知消息推送文本。仅在convType为CUSTOM_PERSON或CUSTOM_TEAM时含此字段',
  `ext` varchar(64) DEFAULT '' COMMENT '消息扩展字段',
  `antispam` varchar(12) DEFAULT '' COMMENT '标识是否被反垃圾(‘’,true,false)',
  `yidun_res` varchar(500) DEFAULT '' COMMENT '易盾反垃圾的原始处理细节',
  `msg_status` tinyint(4) DEFAULT '0' COMMENT '消息发送状态:0-发送成功,1-发送中,2-发送失败',
  `status` tinyint(4) DEFAULT '0' COMMENT '状态:有效 0:无效',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_tt` (`id`,`team_msg_id`,`team_client_msg_id`) USING BTREE,
  KEY `index_team_id_on_im_team_message` (`team_id`),
  KEY `index_send_at_on_im_team_message` (`send_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IM消息表';

SET FOREIGN_KEY_CHECKS = 1;

/*
 Navicat Premium Data Transfer

 Source Server         : 192.168.89.53
 Source Server Type    : MySQL
 Source Server Version : 50726
 Source Host           : 192.168.89.53:3306
 Source Schema         : ddky_im_bis

 Target Server Type    : MySQL
 Target Server Version : 50726
 File Encoding         : 65001

 Date: 08/03/2020 13:18:39
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for im_team_message
-- ----------------------------
DROP TABLE IF EXISTS `im_team_message2`;
CREATE TABLE `im_team_message2` (
  `id` bigint(20) NOT NULL COMMENT '主键id',
  `team_msg_id` bigint(20) DEFAULT NULL COMMENT '群消息id(服务端生成消息id)',
  `team_client_msg_id` varchar(32) DEFAULT '' COMMENT '群消息id(客户端生成)',
  `team_id` bigint(20) DEFAULT NULL COMMENT '群组id(对应群组的accid)',
  `msg_type` varchar(15) DEFAULT 'TEXT' COMMENT '消息类型:TEXT-文本,PICTURE-图片,AUDIO-音频,VIDEO-视频,FILE-文件,GEO-地理位置,CUSTOM-自定义,TIP-提醒,ROBOT-AI机器人,NOTICATION-群通知,TEAM_INVITE-邀请入群,TEAM_INVITE_REJECT-拒绝邀请,CUSTOM_TEAM_MSG -群组自定义系统通知',
  `event_type` tinyint(4) DEFAULT '1' COMMENT '事件类型:1-会话类型消息(p2p消息、群聊消息、自定义系统通知、云信内置系统通知),2-登录事件,3-登出/离线事件,4-聊天室聊天消息,5-音视频时长、白板时长消息,6-音视频白板大小、下载地址消息,7-单聊消息撤回,8-群聊消息撤回,9-汇报主播、管理员进出聊天室事件消息,10-汇报专线电话通话结束回调抄送的消息,11-汇报短信回执抄送的消息,12-汇报短信上行消息,13-汇报用户进出音视频/白板房间的消息,14-汇报聊天室队列操作的事件消息,20-易盾异步反垃圾结果信息',
  `remind_type` tinyint(4) DEFAULT '0' COMMENT '提醒类型:0-普通消息,1-客服进入,2-客户进入,3-客服进入欢迎提醒,4-敏感词命中提醒消息',
  `conv_type` varchar(20) DEFAULT '' COMMENT '场景类型:TEAM',
  `scene` tinyint(4) DEFAULT '0' COMMENT '场景:0-team,1-p2p,2-superTeam',
  `text` varchar(5000) DEFAULT '' COMMENT '内容',
  `attach` varchar(5000) DEFAULT '' COMMENT '附加消息',
  `team_attach_type` tinyint(4) DEFAULT NULL COMMENT '群通知类型:默认null(普通消息),0-更新群,1-拉人入群,2-踢人出群,3-接受入群邀请,4-通过入群邀请,5-添加群管理员,6-移除群管理员,7-主动退群,8-解散群,9-转让群,10-更新群成员禁言状态',
  `send_type` tinyint(4) DEFAULT '0' COMMENT '发送人类型:0-用户,1-客服,2-药师,3-医生',
  `send_client_ip` varchar(20) DEFAULT '' COMMENT '发送端ip',
  `send_client_port` varchar(5) DEFAULT '' COMMENT '发送端端口',
  `send_client_type` varchar(10) DEFAULT '' COMMENT '发送客户端类型: AOS、IOS、PC、WINPHONE、WEB、REST',
  `send_device_id` varchar(32) DEFAULT '' COMMENT '发送端设备编号',
  `send_nick` varchar(50) DEFAULT '' COMMENT '发送人昵称',
  `send_id` varchar(32) DEFAULT '' COMMENT '发送人id(对应客服表和用户表的accid)',
  `send_at` bigint(11) DEFAULT NULL COMMENT '发送时间',
  `msg_receipt_time` bigint(11) DEFAULT NULL COMMENT '已读回执时间戳,如果有此字段, 说明此时间戳之前的所有消息对方均已读',
  `is_revoke` tinyint(4) DEFAULT '0' COMMENT '是否撤销:0-否,1-是',
  `revoke_at` bigint(11) DEFAULT '0' COMMENT '撤销时间',
  `custom_apns_text` varchar(200) DEFAULT '' COMMENT '自定义系统通知消息推送文本。仅在convType为CUSTOM_PERSON或CUSTOM_TEAM时含此字段',
  `ext` varchar(64) DEFAULT '' COMMENT '消息扩展字段',
  `antispam` varchar(12) DEFAULT '' COMMENT '标识是否被反垃圾(‘’,true,false)',
  `yidun_res` varchar(500) DEFAULT '' COMMENT '易盾反垃圾的原始处理细节',
  `msg_status` tinyint(4) DEFAULT '0' COMMENT '消息发送状态:0-发送成功,1-发送中,2-发送失败',
  `status` tinyint(4) DEFAULT '0' COMMENT '状态:有效 0:无效',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_tt` (`id`,`team_msg_id`,`team_client_msg_id`) USING BTREE,
  KEY `index_team_id_on_im_team_message` (`team_id`),
  KEY `index_send_at_on_im_team_message` (`send_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IM消息表';

SET FOREIGN_KEY_CHECKS = 1;




配置分库分表与读写分离

根据群id进行分库,根据群消息id进行分表,详细配置见下:

server.port=8888
spring.main.allow-bean-definition-overriding=true

#---------------------------------
#   mybatis
#---------------------------------
mybatis.type-aliases-package=com.zzx.sharding.entity
#mybatis.type-handlers-package=com.example.typehandler
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=3000
mybatis.mapper-locations=classpath*:mapper/*.xml

#--------------------------------
#   druid
#---------------------------------
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.filters=stat,wall,log4j2
spring.datasource.druid.max-active=50
spring.datasource.druid.initial-size=2
spring.datasource.druid.max-wait=60000
spring.datasource.druid.min-idle=2
spring.datasource.druid.keep-alive=true
spring.datasource.druid.time-between-eviction-runs-millis=60000
spring.datasource.druid.min-evictable-idle-time-millis=300000
spring.datasource.druid.validation-query=select 'x'
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.test-on-borrow=false
spring.datasource.druid.test-on-return=false
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-open-prepared-statements=20
spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000;
spring.datasource.druid.use-global-data-source-stat=true
spring.datasource.druid.web-stat-filter.enabled=true
spring.datasource.druid.web-stat-filter.url-pattern=/*
spring.datasource.druid.web-stat-filter.exclusions='*.gif,*.png,*.jpg,*.html,*.js,*.css,*.ico,/druid/*'
spring.datasource.druid.stat-view-servlet.enabled=true
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.druid.stat-view-servlet.reset-enable=true
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=admin

# 配置日志输出
spring.datasource.druid.filter.log4j2.enabled=true
spring.datasource.druid.filter.log4j2.statement-create-after-log-enabled=false
spring.datasource.druid.filter.log4j2.statement-close-after-log-enabled=false
spring.datasource.druid.filter.log4j2.result-set-open-after-log-enabled=false
spring.datasource.druid.filter.log4j2.result-set-close-after-log-enabled=false

#--------------------------------
#   ShardingSphere
#---------------------------------
#打印sql
spring.shardingsphere.props.sql.show=true

spring.shardingsphere.datasource.names=master0,slave0,master1,slave1

spring.shardingsphere.datasource.master0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master0.url=jdbc:mysql://localhost:3342/im_bis?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
spring.shardingsphere.datasource.master0.username=root
spring.shardingsphere.datasource.master0.password=123456

spring.shardingsphere.datasource.slave0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave0.url=jdbc:mysql://localhost:3343/im_bis?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
spring.shardingsphere.datasource.slave0.username=root
spring.shardingsphere.datasource.slave0.password=123456

spring.shardingsphere.datasource.master1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master1.url=jdbc:mysql://localhost:3344/im_bis?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
spring.shardingsphere.datasource.master1.username=root
spring.shardingsphere.datasource.master1.password=123456

spring.shardingsphere.datasource.slave1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave1.url=jdbc:mysql://localhost:3345/im_bis?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
spring.shardingsphere.datasource.slave1.username=root
spring.shardingsphere.datasource.slave1.password=123456

#根据群id分库
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=team_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=master$->{team_id % 2}
#根据群消息id分表
spring.shardingsphere.sharding.tables.im_team_message.actual-data-nodes=master$->{0..1}.im_team_message$->{0..2}
spring.shardingsphere.sharding.tables.im_team_message.table-strategy.inline.sharding-column=team_msg_id
spring.shardingsphere.sharding.tables.im_team_message.table-strategy.inline.algorithm-expression=im_team_message$->{team_msg_id % 3}
# 废弃
#spring.shardingsphere.sharding.tables.im_team_message.key-generator.column=id
#spring.shardingsphere.sharding.tables.im_team_message.key-generator.type=SNOWFLAKE
#spring.shardingsphere.sharding.tables.im_team_message.key-generator.props.worker.id=123

#指定master0为主库,slave0为它的从库
spring.shardingsphere.sharding.master-slave-rules.master0.master-data-source-name=master0
spring.shardingsphere.sharding.master-slave-rules.master0.slave-data-source-names=slave0
#指定master1为主库,slave1为它的从库
spring.shardingsphere.sharding.master-slave-rules.master1.master-data-source-name=master1
spring.shardingsphere.sharding.master-slave-rules.master1.slave-data-source-names=slave1

验证

添加数据——写入主库0或主库1

postman执行: localhost:8888/teamMessage/batchAdd

代码

@PostMapping("batchAdd")
public ServiceResponse batchAdd(HttpServletRequest request, HttpServletResponse response) throws IOException {
    ServiceResponse result = new ServiceResponse<>();
    for (int i = 0; i < 20; i++) {
        TeamMessage vo = new TeamMessage();
        vo.setSendAt(new Date().getTime());
        vo.setTeamId(1000);
        vo.setTeamClientMsgId(UUID.randomUUID().toString());
        vo.setTeamMsgId(SnowIdUtils.uniqueLong());
        vo.setId(SnowIdUtils.uniqueLong());
        vo.setText("消息内容-"+UUID.randomUUID());
        this.teamMessageServiceApi.insert(vo);
    }
    result.setCode(ResponseEnum.SUCCESS.getCode());
    result.setMsg(ResponseEnum.SUCCESS.getName());
    return result;
}
  •  

群id为1000时,路由到主库0,写入主库0成功

日志

2020-03-11 18:25:06.525  INFO 46360 --- [nio-8888-exec-8] ShardingSphere-SQL                       : Actual SQL: master0 ::: INSERT IGNORE INTO ....
  • 1

主库0:表中的数据根据群消息id路由到各表中
Java猿社区—ShardingSphere4.0.0-RC1实现分库分表+读写分离
Java猿社区—ShardingSphere4.0.0-RC1实现分库分表+读写分离
Java猿社区—ShardingSphere4.0.0-RC1实现分库分表+读写分离

主库1: 表中没有数据
Java猿社区—ShardingSphere4.0.0-RC1实现分库分表+读写分离
群id为1001时,路由到主库1,写入主库1成功

日志

2020-03-11 18:30:12.345  INFO 46360 --- [nio-8888-exec-8] ShardingSphere-SQL                       : Actual SQL: master1 ::: INSERT IGNORE INTO ....
  • 1

主库1:表中的数据根据群消息id路由到各表中
Java猿社区—ShardingSphere4.0.0-RC1实现分库分表+读写分离
Java猿社区—ShardingSphere4.0.0-RC1实现分库分表+读写分离
Java猿社区—ShardingSphere4.0.0-RC1实现分库分表+读写分离

主库0: 表中没有新增数据
Java猿社区—ShardingSphere4.0.0-RC1实现分库分表+读写分离

分库验证成功!

查询数据——从库查询

查询所有数据
Java猿社区—ShardingSphere4.0.0-RC1实现分库分表+读写分离

由于分库,且每个主库仅一个从库,我们执行查询所有数据操作,shardingsphere会帮我们从各从库各分表中采用聚合的方式获取数据。后面会根据shardingsphere原理单独说明如何对聚合的数据进行操作。

控制台sql日志:

2020-03-11 18:35:29.399  INFO 46360 --- [nio-8888-exec-1] ShardingSphere-SQL                       : Rule Type: sharding
2020-03-11 18:35:29.399  INFO 46360 --- [nio-8888-exec-1] ShardingSphere-SQL                       : Logic SQL: SELECT id,。。。。。 FROM im_team_message WHERE STATUS = 0 			


2020-03-11 18:35:29.399  INFO 46360 --- [nio-8888-exec-1] ShardingSphere-SQL                       : SQLStatement: SelectStatement(super=DQLStatement(super=AbstractSQLStatement(type=DQL, tables=Tables(tables=[Table(name=im_team_message, alias=Optional.absent())]), routeConditions=Conditions(orCondition=OrCondition(andConditions=[])), encryptConditions=Conditions(orCondition=OrCondition(andConditions=[])), sqlTokens=[TableToken(tableName=im_team_message, quoteCharacter=NONE, schemaNameLength=0)], parametersIndex=0, Logic SQL: SELECT id,。。。。。 FROM im_team_message WHERE status = 0)), containStar=false, firstSelectItemStartIndex=14, selectListStopIndex=410, groupByLastIndex=0, items=[CommonSelectItem(expression=id, alias=Optional.absent()), CommonSelectItem(expression=team_msg_id, alias=Optional.absent()), CommonSelectItem(expression=team_client_msg_id, alias=Optional.absent()), CommonSelectItem(expression=msg_type, alias=Optional.absent()), CommonSelectItem(expression=remind_type, alias=Optional.absent()), CommonSelectItem(expression=conv_type, alias=Optional.absent()), CommonSelectItem(expression=scene, alias=Optional.absent()), CommonSelectItem(expression=text, alias=Optional.absent()), CommonSelectItem(expression=team_attach_type, alias=Optional.absent()), CommonSelectItem(expression=send_type, alias=Optional.absent()), CommonSelectItem(expression=send_client_ip, alias=Optional.absent()), CommonSelectItem(expression=send_client_port, alias=Optional.absent()), CommonSelectItem(expression=send_client_type, alias=Optional.absent()), CommonSelectItem(expression=send_device_id, alias=Optional.absent()), CommonSelectItem(expression=send_nick, alias=Optional.absent()), CommonSelectItem(expression=team_id, alias=Optional.absent()), CommonSelectItem(expression=send_id, alias=Optional.absent()), CommonSelectItem(expression=send_at, alias=Optional.absent()), CommonSelectItem(expression=msg_receipt_time, alias=Optional.absent()), CommonSelectItem(expression=is_revoke, alias=Optional.absent()), CommonSelectItem(expression=revoke_at, alias=Optional.absent()), CommonSelectItem(expression=msg_status, alias=Optional.absent()), CommonSelectItem(expression=event_type, alias=Optional.absent()), CommonSelectItem(expression=status, alias=Optional.absent()), CommonSelectItem(expression=attach, alias=Optional.absent()), CommonSelectItem(expression=custom_apns_text, alias=Optional.absent()), CommonSelectItem(expression=ext, alias=Optional.absent()), CommonSelectItem(expression=antispam, alias=Optional.absent()), CommonSelectItem(expression=yidun_res, alias=Optional.absent())], groupByItems=[], orderByItems=[], limit=null, subqueryStatement=null, subqueryStatements=[], subqueryConditions=[])

2020-03-11 18:35:29.399  INFO 46360 --- [nio-8888-exec-1] ShardingSphere-SQL                       : Actual SQL: slave0 ::: select  。。。。
。。。

2020-03-11 18:35:29.399  INFO 46360 --- [nio-8888-exec-1] ShardingSphere-SQL                       : Actual SQL: slave1 ::: select
。。。

  •  

部分日志省略,从上面可以看得出,查询所有数据时候,shardingsphere从从库0和从库1各表中将数据进行聚合处理返回给调用接口。

返回数据
Java猿社区—ShardingSphere4.0.0-RC1实现分库分表+读写分离

由于执行了两次两个群组的新增数据,总共40条数据

分库分表验证成功!

问题记录

springboot2.1.5默认使用mysql-connECTOR-java8.x的版本,这个版本的驱动使用shardingsphere时会有bug,推荐使用mysql-connector-java5.1.47版本

上一篇:scrum指南2020最新版带来哪些变化?


下一篇:如何创办一场算法竞赛