Apache ShardingSphere(二) 基本使用

news2025/7/20 12:59:31

文章目录

  • 二 ShardingSphere JDBC 基本使用
    • 2.1 ShardingSphere JDBC 水平分表
      • 2.1.1 案例入门
      • 2.1.2 解读配置文件
      • 2.1.3 其他测试
      • 2.1.4 延伸问题
    • 2.2 ShardingSphere JDBC 水平分库
      • 2.2.1 案例入门
      • 2.2.2 解读配置文件
      • 2.1.3 其他测试
    • 2.3 ShardingSphere JDBC 广播表
      • 2.3.1 基本案例入门
      • 2.3.2 扩展
    • 2.4 ShardingSphere JDBC 读写分离
      • 2.4.1 Mysql主从复制环境搭建
        • 2.4.1.1 安装Docker,Docker-Compose
        • 2.4.1.2 新建文件
        • 2.4.1.3 启动测试
        • 2.4.1.4 其他
      • 2.4.2 准备工作
      • 2.4.3 入门案例
      • 2.4.4 会产生的问题?
        • 2.4.4.1 可能从库会出现读延迟,导致查询不到数据?

二 ShardingSphere JDBC 基本使用

2.1 ShardingSphere JDBC 水平分表

2.1.1 案例入门

  • sql
DROP TABLE IF EXISTS t_order_1;
CREATE TABLE t_order_1(
  order_id varchar(255) NOT NULL   COMMENT '订单编号' ,
  order_time DATETIME NOT NULL   COMMENT '订单时间' ,
  order_money DECIMAL(24,6) NOT NULL   COMMENT '订单金额' ,
  user_id INT NOT NULL   COMMENT '订单下单人' ,
  PRIMARY KEY (order_id)
)  COMMENT = '订单表';


DROP TABLE IF EXISTS t_order_2;
CREATE TABLE t_order_2(
  order_id INT NOT NULL   COMMENT '订单编号' ,
  order_time DATETIME NOT NULL   COMMENT '订单时间' ,
  order_money DECIMAL(24,6) NOT NULL   COMMENT '订单金额' ,
  user_id INT NOT NULL   COMMENT '订单下单人' ,
  PRIMARY KEY (order_id)
)  COMMENT = '订单表';


DROP TABLE IF EXISTS t_dict;
CREATE TABLE t_dict(
    dict_id INT(11) NOT NULL AUTO_INCREMENT  COMMENT '字典id' ,
    dict_fid INT(11)    COMMENT '所属字典;上级id;0:为字典类型,其余为该字典类型下的值' ,
    dict_label VARCHAR(255)    COMMENT '字典名称;字典名称' ,
    dict_value VARCHAR(255)    COMMENT '字典值' ,
    dict_code VARCHAR(255)    COMMENT '字典唯一编码' ,
    create_time DATETIME    COMMENT '创建时间' ,
    remark VARCHAR(255)    COMMENT '备注' ,
    is_delete VARCHAR(1) NOT NULL  DEFAULT 1 COMMENT '是否删除;0:已删除;1:未删除' ,
    PRIMARY KEY (dict_id)
)  COMMENT = '字典信息表';


依赖

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


  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.5</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <groupId>com.shu</groupId>
  <artifactId>v1</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>Sharding-Jdbc-V4.0-Demo</name>
  <description>Sharding-Jdbc-V4.0-Demo</description>

  <properties>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>

    <!--  mybatis依赖 -->
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.0.0</version>
    </dependency>


    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>1.2.5</version>
    </dependency>


    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>



    <dependency>
      <groupId>org.apache.shardingsphere</groupId>
      <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
      <version>4.0.0-RC1</version>
    </dependency>




    <!--swagger2依赖-->
    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger2</artifactId>
      <version>2.9.2</version>
    </dependency>

    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger-ui</artifactId>
      <version>2.9.2</version>
    </dependency>


    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.22</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>


    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>5.8.1</version>
      <scope>test</scope>
    </dependency>
    </dependencies>

      <build>
      <plugins>
      <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <configuration>
      <excludes>
      <exclude>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </exclude>
    </excludes>
    </configuration>
    </plugin>
    </plugins>
    </build>

    </project>

  • 实体类
package com.shu.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;

/**
* @description:
* @author: shu
* @createDate: 2022/11/24 9:57
* @version: 1.0
*/
@Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Dict {
        /** 字典id */
        @ApiModelProperty(name = "字典id",notes = "")
        private Integer dictId ;
        /** 所属字典;上级id;0:为字典类型,其余为该字典类型下的值 */
        @ApiModelProperty(name = "所属字典",notes = "上级id;0:为字典类型,其余为该字典类型下的值")
        private Integer dictFid ;
        /** 字典名称;字典名称 */
        @ApiModelProperty(name = "字典名称",notes = "字典名称")
        private String dictLabel ;
        /** 字典值 */
        @ApiModelProperty(name = "字典值",notes = "")
        private String dictValue ;
        /** 字典唯一编码 */
        @ApiModelProperty(name = "字典唯一编码",notes = "")
        private String dictCode ;
        /** 创建时间 */
        @ApiModelProperty(name = "创建时间",notes = "")
        @JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
        private Date createTime ;
        /** 备注 */
        @ApiModelProperty(name = "备注",notes = "")
        private String remark ;
        /** 是否删除;0:已删除;1:未删除 */
        @ApiModelProperty(name = "是否删除",notes = "0:已删除;1:未删除")
        private String isDelete ;
    }





package com.shu.model;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;

/**
 * @description: 订单实体类
 * @author: shu
 * @createDate: 2022/8/4 15:13
 * @version: 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
    /** 订单编号 */
    @ApiModelProperty(name = "订单编号",notes = "")
    private String orderId ;
    /** 订单时间 */
    @ApiModelProperty(name = "订单时间",notes = "")
    @JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
    private Date orderTime ;
    /** 订单金额 */
    @ApiModelProperty(name = "订单金额",notes = "")
    private Double orderMoney ;
    /** 订单下单人 */
    @ApiModelProperty(name = "订单下单人",notes = "")
    private Integer userId ;
}






  • 增删改查的编写就省略了
  • 配置文件(请注意这4.0的配置文件,5.0版本还是有很大差别的)
# 开启大驼峰命名法
mybatis:
  configuration:
    map-underscore-to-camel-case: true
# 分库分表配置
spring:
  main:
    allow-bean-definition-overriding: true
  sharding-sphere:
    datasource:
      # 数据源名称
      names: d1,m3
      # 数据源d1配置
      d1.type: com.alibaba.druid.pool.DruidDataSource
      d1.url: jdbc:mysql://localhost:3306/order_db_1?useUnicode=true&characterEncoding=utf8
      d1.username: root
      d1.password: 123456
      d1.driverClassName: com.mysql.cj.jdbc.Driver
      # 其他数据源配置
      m3.type: com.alibaba.druid.pool.DruidDataSource
      m3.url: jdbc:mysql://localhost:3306/auth?useUnicode=true&characterEncoding=utf8
      m3.username: root
      m3.password: 123456
      m3.driverClassName: com.mysql.cj.jdbc.Driver

    # 简单分片规则配置
    sharding:
        tables:
          # 订单表
          t_order.actual_data_nodes: d1.t_order_$->{1..2}
          # 订单主键
          t_order.key-generator.column: order_id
          # 订单主键生成策略,主键生成策略为雪花算法
          t_order.key-generator.type: Snowflake
          # 定义分片键
          t_order.table-strategy.inline.sharding-column: user_id
          # 定义分片策略
          t_order.table-strategy.inline.algorithm-expression: t_order_$->{user_id % 2 + 1}

#### 展示sql运行日志##############
    props:
      sql:
        show: true
  • 测试

image.png

2.1.2 解读配置文件

  • 数据源配置
spring:
  main:
    allow-bean-definition-overriding: true
  sharding-sphere:
    datasource:
      # 数据源名称
      names: d1,m3 
      # 数据源d1配置
      d1.type: #数据库连接池类型
      d1.url: #数据库url
      d1.username: #账号
      d1.password: # 密码
      d1.driverClassName: 
      # 其他数据源配置
      m3.type: 
      m3.url:
      m3.username: 
      m3.password:
      m3.driverClassName: 
  • 实际数据节点
 sharding:
        tables:
          # 订单表
          【需要进行分片的表名】.actual_data_nodes: 实际是数据节点
  • 主键生成策越
 sharding:
        tables:
          # 订单主键
          【需要进行分片的表名】.key-generator.column: 主键字段
          # 订单主键生成策略,主键生成策略为雪花算法,UUID
         【需要进行分片的表名】.key-generator.type: Snowflake
  • 分片键策越
  sharding:
        tables:
          # 定义分片键
         【需要进行分片的表名】.table-strategy.inline.sharding-column: 分片键字段
          # 定义分片策略
        【需要进行分片的表名】.table-strategy.inline.algorithm-expression: 行表达式

2.1.3 其他测试

插入测试:是否生成唯一主键?
image.png
注意:Mybatis不用写主键插入
image.png
查询测试:是否会查询全部数据?
image.png
单个数据查询呢?
image.png
image.png
更新数据呢?
image.png
我们可以看到,上面是查询都走了两张表,全表路由造成性能浪费,携带上分片键查询。
image.png

2.1.4 延伸问题

主要的分片算法?

参考文章:Sharding-JDBC 实战(史上最全)_40岁资深老架构师尼恩的博客-CSDN博客_sharding-jdbc

  • range 分片

一种是按照 range 来分,就是每个片,一段连续的数据,这个一般是按比如时间范围/数据范围来的,但是这种一般较少用,因为很容易发生数据倾斜,大量的流量都打在最新的数据上了。

  • ID取模分片

此种分片规则将数据分成n份(通常dn节点也为n),从而将数据均匀的分布于各个表中,或者各节点上。

  • hash 哈希分片

使用hash 算法,获取key的哈希结果,再按照规则进行分片,这样可以保证数据被打散,同时保证数据分布的比较均匀

当我们的sql语句中存在mysql 自带的函数是否能解析?

image.png

image.png
image.png
踩坑日记?

2.2 ShardingSphere JDBC 水平分库

2.2.1 案例入门

image.png
结构与上面一样,主要是配置文件的不同

  • 配置文件
# 开启大驼峰命名法
mybatis:
configuration:
map-underscore-to-camel-case: true
# 分库分表配置
spring:
main:
allow-bean-definition-overriding: true
sharding-sphere:
datasource:
# 数据源名称
names: d1,d2,d3
# 数据源d1配置
d1.type: com.alibaba.druid.pool.DruidDataSource
d1.url: jdbc:mysql://localhost:3306/order_db_1?useUnicode=true&characterEncoding=utf8
d1.username: root
d1.password: 123456
d1.driverClassName: com.mysql.cj.jdbc.Driver
# 数据源d2配置
d2.type: com.alibaba.druid.pool.DruidDataSource
d2.url: jdbc:mysql://localhost:3306/order_db_2?useUnicode=true&characterEncoding=utf8
d2.username: root
d2.password: 123456
d2.driverClassName: com.mysql.cj.jdbc.Driver
# 数据源d3配置
m3.type: com.alibaba.druid.pool.DruidDataSource
m3.url: jdbc:mysql://localhost:3306/order_db_3?useUnicode=true&characterEncoding=utf8
m3.username: root
m3.password: 123456
m3.driverClassName: com.mysql.cj.jdbc.Driver

# 简单分片规则配置
sharding:
tables:
# 订单表
t_order.actual_data_nodes: d$->{1..3}.t_order
# 订单主键
t_order.key-generator.column: order_id
# 订单主键生成策略,主键生成策略为UUID
t_order.key-generator.type: UUID
# 定义分片键
t_order.database-strategy.inline.sharding-column: user_id
# 定义分片策略
t_order.database-strategy.inline.algorithm-expression: d$->{user_id % 3 + 1}


#### 展示sql运行日志##############
props:
sql:
show: true
  • 测试

image.png

2.2.2 解读配置文件

  • 数据源配置
spring:
  main:
    allow-bean-definition-overriding: true
  sharding-sphere:
    datasource:
      # 数据源名称
      names: d1,d2 
      # 数据源d1配置
      d1.type: #数据库连接池类型
      d1.url: #数据库url
      d1.username: #账号
      d1.password: # 密码
      d1.driverClassName: 
      # 其他数据源配置
      d2.type: 
      d2.url:
      d2.username: 
      d2.password:
      d2.driverClassName: 

与水平分表不一样的是,这里我们配置了多个数据源,且数据源表结构是一样

  • 实际数据节点
 sharding:
        tables:
          # 订单表
          【需要进行分片的表名】.actual_data_nodes: 实际是数据库节点,不是表节点
  • 主键生成策越
 sharding:
        tables:
          # 订单主键
          【需要进行分片的表名】.key-generator.column: 主键字段
          # 订单主键生成策略,主键生成策略为雪花算法,UUID
         【需要进行分片的表名】.key-generator.type: Snowflake
  • 分片键策越
  sharding:
        tables:
          # 定义分片键
         【需要进行分片的表名】.table-strategy.inline.sharding-column: 分片键字段
          # 定义分片策略
        【需要进行分片的表名】.table-strategy.inline.algorithm-expression: 数据库行表达式

2.1.3 其他测试

插入测试?
image.png
查询测试?
image.png
更新测试?
image.png

2.3 ShardingSphere JDBC 广播表

2.3.1 基本案例入门

  • 广播表也叫全局表,也就是它会存在于多个库中冗余,避免跨库查询问题。
  • 比如省份、字典等一些基础数据,为了避免分库分表后关联表查询这些基础数据存在跨库问题,所以可以把这些数据同步给每一个数据库节点,这个就叫广播表。

结构与前面一样,主要是配置
image.png

  • 测试

插入测试
image.png
查询:会随机选择一个数据源进行查询
image.png
更新
image.png
删除
image.png

2.3.2 扩展

如果我只想查询走我指定的库,应该怎么办?

  • 依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • 自定义注解
package com.shu.aspect;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @description: 自定义注解走某个库
 * @author: shu
 * @createDate: 2022/11/22 13:32
 * @version: 1.0
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface DBMaster {
}


package com.shu.aspect;

import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.hint.HintManager;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @description:
 * @author: shu
 * @createDate: 2022/11/22 13:32
 * @version: 1.0
 */
@Slf4j
@Component
@Aspect
public class DBMasterHandler {

    @Around("execution(* com.shu.mapper.*.*(..))")
    public Object master(ProceedingJoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        Object ret = null;
        log.info(joinPoint.toShortString());
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        DBMaster dBMaster = method.getAnnotation(DBMaster.class);
        HintManager hintManager = null;
        try {
            if (Objects.nonNull(dBMaster)) {
                HintManager.clear();
                hintManager = HintManager.getInstance();
                hintManager.setDatabaseShardingValue("d1");
            }
            ret = joinPoint.proceed(args);
        }catch (Exception ex){
            log.error("exception error",ex);
        }catch (Throwable ex2){
            log.error("Throwable",ex2);
        }finally {
            if (Objects.nonNull(dBMaster) && Objects.nonNull(hintManager)) {
                hintManager.close();
            }
        }
        return ret;
    }
}

  • 自定义分片算法
package com.shu.aspect;

import org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.hint.HintShardingValue;
import java.util.Collection;
import java.util.Collections;


/**
 * @description:
 * @author: shu
 * @createDate: 2022/11/22 14:12
 * @version: 1.0
 */
public class HintShardingKeyAlgorithm implements HintShardingAlgorithm<Integer> {


    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<Integer> shardingValue) {
        String key = (String) shardingValue.getValues().toArray()[0];
        if(availableTargetNames.contains(key)){
            return Collections.singletonList(key);
        }
        throw new UnsupportedOperationException("route "+ key +" is not supported ,please check your config");
    }

}
  • 配置
####################默认路由算法############
spring.shardingsphere.sharding.default-database-strategy.hint.algorithm-class-name=com.shu.aspect.HintShardingKeyAlgorithm
  • 在查询mapper上加上注解

image.png

  • 测试

image.png
可以看到我们每次查询走了144
思考?
当我们更新字典表是,突然其中一台数据库挂了,新增数据库字典正在运行,你会发现,其中有数据库,更新成功,有的则失败,当我们再次查询时会出现数据不一致的问题?怎么解决?

2.4 ShardingSphere JDBC 读写分离

2.4.1 Mysql主从复制环境搭建

2.4.1.1 安装Docker,Docker-Compose

  • 安装Docker
#1.卸载旧版本
yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
#2.需要的安装包
yum install -y yum-utils
#3.设置镜像的仓库
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
#默认是从国外的,不推荐
#推荐使用国内的
yum-config-manager \
    --add-repo \
    https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#更新yum软件包索引
yum makecache fast
#4.安装docker相关的 docker-ce 社区版 而ee是企业版
yum install docker-ce docker-ce-cli containerd.io
#5、启动docker
#root用户
systemctl start docker 
#非root用户
sudo systemctl start docker
#6. 使用docker version查看是否按照成功
docker version

  • 安装Docker-Compose
sudo curl -L "https://get.daocloud.io/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

如有需要,修改上面 1.24.1 为指定版本号即可

  • 安装完后执行
sudo chmod +x /usr/local/bin/docker-compose
  • 验证
docker-compose version

2.4.1.2 新建文件

image.png

  • docker-compose.yml:编写文件如下
version: "2"
services:
   mysql-master:
     image: mysql:5.7
     ports:
       - 3340:3306
     volumes:
       - ./conf-master:/etc/mysql/conf.d 
       - ./data-master:/var/lib/mysql
       - ./conf-master:/etc/mysql/mysql.conf.d
     environment:
       MYSQL_ROOT_PASSWORD: 123456
       MYSQL_DATABASE: db
       MYSQL_USER: user
       MYSQL_PASSWORD: user123
     restart: always
     container_name: mysql-master
   mysql-slave:
     image: mysql:5.7
     ports:
       - 3341:3306
     volumes:
       - ./conf-slave:/etc/mysql/conf.d
       - ./data-slave:/var/lib/mysql
       - ./conf-slave:/etc/mysql/mysql.conf.d
     environment:
       MYSQL_ROOT_PASSWORD: 123456
       MYSQL_DATABASE: db
       MYSQL_USER: user
       MYSQL_PASSWORD: user123
     restart: always
     container_name: mysql-slave
  • 先建conf-master,conf-slave,mysql运行配置文件夹

编写数据库配置文件

conf-master 配置文件my.cnf

[mysqld]
server-id=101
log-bin=mysql-bin
binlog_format=MIXED
max_binlog_size = 124M
expire_logs_days = 3
binlog_ignore_db = mysql,performance_schema,information_schema,sys

conf-slave 配置文件my.cnf

[mysqld]
server_id = 1002
log_bin = mysql-bin
binlog_format=MIXED
max_binlog_size = 124M
expire_logs_days = 3
replicate-ignore-db=mysql,performance_schema,information_schema,sy
relay_log_recovery = 1
log_slave_updates = 1

image.png

  • 其他文件夹

data-master(mysql数据卷) logs-master(mysql日志文件)
data-slave(mysql数据卷) logs-slave(mysql日志文件)

2.4.1.3 启动测试

主库配置

# Docker-compose编译
[root@ecs-341636 MysqlMs]# docker-compose up -d
Creating network "mysqlms_default" with the default driver
Creating mysql-slave  ... done
Creating mysql-master ... done
# 进入容器
[root@ecs-341636 MysqlMs]# docker exec -it mysql-master bash
# 连接
bash-4.2# mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.40-log MySQL Community Server (GPL)

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
# 查看配置信息
mysql> show variables like '%server_id%';
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| server_id      | 101   |
| server_id_bits | 32    |
+----------------+-------+
2 rows in set (0.01 sec)
# 查看主节点状态
mysql> show master status;
+------------------+----------+--------------+-------------------------------------------------------------------------------------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB                                                                                | Executed_Gtid_Set |
+------------------+----------+--------------+-------------------------------------------------------------------------------------------------+-------------------+
| mysql-bin.000003 |      154 |              | mysql,performance_schema,information_schema,sys,mysql,performance_schema,information_schema,sys |                   |
+------------------+----------+--------------+-------------------------------------------------------------------------------------------------+-------------------+
1 row in set (0.00 sec)
# 授权
mysql> grant replication slave,replication client on *.* to 'slave'@'%' identified by "123456";
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)


从库配置

[root@ecs-341636 MysqlMs]# docker exec -it mysql-slave bash
bash-4.2# mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.40-log MySQL Community Server (GPL)

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show variables like '%server_id%';
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| server_id      | 1002  |
| server_id_bits | 32    |
+----------------+-------+
2 rows in set (0.00 sec)

mysql> change master to
    -> master_host='127.0.0.1', // 注意阿里云上需要用外网地址
    -> master_user='slave',
    -> master_password='123456',
    -> master_port=3340,
    -> master_log_file='mysql-bin.000001',
    -> master_log_pos= 0,
    -> master_connect_retry=30;

#启动slave
mysql> start slave;
# 查看状态
mysql> show slave status;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.112.3
                  Master_User: slave
                  Master_Port: 3306
                Connect_Retry: 30
              Master_Log_File: mysql-bin.000004
          Read_Master_Log_Pos: 617
               Relay_Log_File: 7fee2f1fd5d2-relay-bin.000002
                Relay_Log_Pos: 783
        Relay_Master_Log_File: mysql-bin.000004
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 617
              Relay_Log_Space: 997
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 8f6e9f5a-61f4-11eb-ac84-0242c0a86002
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.01 sec)
  • master_host :Master的地址,指的是容器的独立ip,可以通过docker inspect --format=‘{{.NetworkSettings.IPAddress}}’ 容器名称|容器id查询容器的ip
  • master_port:Master的端口号,指的是容器的端口号
  • master_user:用于数据同步的用户
  • master_password:用于同步的用户的密码
  • master_log_file:指定 Slave 从哪个日志文件开始复制数据,即上文中提到的 File 字段的值
  • master_log_pos:从哪个 Position 开始读,即上文中提到的 Position 字段的值
  • master_connect_retry:如果连接失败,重试的时间间隔,单位是秒,默认是60秒

上面看到,有两个Yes,说明已经成功了

        Relay_Master_Log_File: mysql-bin.000004
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

image.png
image.png

2.4.1.4 其他

  • 从库设置权限
SHOW VARIABLES LIKE '%read_only%'; #查看只读状态

SET GLOBAL super_read_only=1; #super权限的用户只读状态 1.只读 0:可写
SET GLOBAL read_only=1; #普通权限用户读状态 1.只读 0:可写

  • 服务器命令
stop slave;
start slave;
show slave status;

2.4.2 准备工作

  • 我们在主数据库上创建数据文件
DROP TABLE IF EXISTS t_order_1;
CREATE TABLE t_order_1(
  order_id INT NOT NULL   COMMENT '订单编号' ,
  order_time DATETIME NOT NULL   COMMENT '订单时间' ,
  order_money DECIMAL(24,6) NOT NULL   COMMENT '订单金额' ,
  user_id INT NOT NULL   COMMENT '订单下单人' ,
  PRIMARY KEY (order_id)
)  COMMENT = '订单表';

DROP TABLE IF EXISTS t_order_2;
CREATE TABLE t_order_2(
  order_id INT NOT NULL   COMMENT '订单编号' ,
  order_time DATETIME NOT NULL   COMMENT '订单时间' ,
  order_money DECIMAL(24,6) NOT NULL   COMMENT '订单金额' ,
  user_id INT NOT NULL   COMMENT '订单下单人' ,
  PRIMARY KEY (order_id)
)  COMMENT = '订单表';


DROP TABLE IF EXISTS t_dict;
CREATE TABLE t_dict(
    dict_id INT(11) NOT NULL AUTO_INCREMENT  COMMENT '字典id' ,
    dict_fid INT(11)    COMMENT '所属字典;上级id;0:为字典类型,其余为该字典类型下的值' ,
    dict_label VARCHAR(255)    COMMENT '字典名称;字典名称' ,
    dict_value VARCHAR(255)    COMMENT '字典值' ,
    dict_code VARCHAR(255)    COMMENT '字典唯一编码' ,
    create_time DATETIME    COMMENT '创建时间' ,
    remark VARCHAR(255)    COMMENT '备注' ,
    is_delete VARCHAR(1) NOT NULL  DEFAULT 1 COMMENT '是否删除;0:已删除;1:未删除' ,
    PRIMARY KEY (dict_id)
)  COMMENT = '字典信息表';

image.png
我们不需要从库建表,他会自动同步表结构与数据库结构

2.4.3 入门案例

结构0130D9A0.png与前面一样,关键是配置文件,使用Sharding-JDBC配置读写分离,优点在于数据源完全有Sharding托管,写操作自动执行master库,读操作自动执行slave库。不需要程序员在程序中关注这个实现了。

  • 配置文件
# 开启大驼峰命名法
mybatis:
  configuration:
    map-underscore-to-camel-case: true
# 分库分表配置
spring:
  main:
    allow-bean-definition-overriding: true
  sharding-sphere:
    datasource:
      # 数据源名称
      names: d1,d2
      # 数据源d1配置
      d1.type: com.alibaba.druid.pool.DruidDataSource
      d1.url: jdbc:mysql://ip:3340/db?useUnicode=true&characterEncoding=utf8
      d1.username: root
      d1.password: 123456
      d1.driverClassName: com.mysql.cj.jdbc.Driver
      # 数据源d2配置
      d2.type: com.alibaba.druid.pool.DruidDataSource
      d2.url: jdbc:mysql://ip:3341/db?useUnicode=true&characterEncoding=utf8
      d2.username: root
      d2.password: 123456
      d2.driverClassName: com.mysql.cj.jdbc.Driver

    # 简单分片规则配置
    sharding:
        # 绑定广播表
      broadcast-tables: t_dict

    # 读写分离配置
    masters-lave:
      name: dataSource
      master-data-source-name: d1 # 只能一个
      slave-data-source-names: d2 # 可以多个
      load-balance-algorithm-type: round_robin # 负载均衡算法,可选值:ROUND_ROBIN(轮询),RANDOM(随机)

    #### 展示sql运行日志##############
    props:
      sql:
        show: true
  • 测试

插入操作?
image.png
查询操作?
image.png
更新操作?
image.png
image.png
我们测试可以发现,当我们对数据库进行写操作时,他会走主库,查询操作时他会走从库

2.4.4 会产生的问题?

2.4.4.1 可能从库会出现读延迟,导致查询不到数据?

强制走主库,但是违背了主从复制的初衷

(1)业务层面妥协,是否操作完之后马上要进行读取
(2)对于操作完马上要读出来的,且业务上不能妥协的,我们可以对于这类的读取直接走主库,当然Sharding-JDBC也是考虑到这个问题的存在,所以给我们提供了一个功能,可以让用户在使用的时候指定要不要走主库进行读取。在读取前使用下面的方式进行设置就可以了

        HintManager.clear();
        hintManager = HintManager.getInstance();
		// 强制路由主库
       hintManager.setMasterRouteOnly();

延迟查询,比如主库更新一条数据以后,查询从库数据的时候后端接口可以线sleep一段时间,比如绝大多数主从同步都可以在1s内完成,那就可以sleep一秒钟的时间。或者也可以延迟查询逻辑放在前端,比如订单支付完成后,可以前端延迟一秒再发起Ajax请求。

参考官网:
https://shardingsphere.apache.org/document/current/cn/features/sharding/limitation/
参考文章:
https://blog.csdn.net/crazymakercircle/article/details/123420859
https://blog.csdn.net/weixin_36586120/article/details/118018414
https://tech.meituan.com/2017/04/21/mt-leaf.html
https://blog.csdn.net/sinat_32873711/article/details/128029810

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/35861.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

矩阵链相乘(动态规划)

【问题描述】给定n个矩阵M1,M2...MnM_1,M_2...M_nM1​,M2​...Mn​&#xff0c;他们的维数分别是r1∗c1,r2∗c2...rn∗cnr_1*c_1,r_2*c_2...r_n*c_nr1​∗c1​,r2​∗c2​...rn​∗cn​&#xff0c;要求使用【动态规划】的策略求解矩阵连乘的最优计算代价(总乘法次数最少)。题目…

Docker 学习视频集 bilibili

1.什么是Docker_哔哩哔哩_bilibili 2.Docker的安装_哔哩哔哩_bilibili 3.镜像、容器和仓库_哔哩哔哩_bilibili 4.在容器中部署一个应用_哔哩哔哩_bilibili 5.将容器保存成镜像成片_哔哩哔哩_bilibili 6.使用Dockerfile构建镜像1_哔哩哔哩_bilibili 7.导入导出镜像_哔哩哔…

vscode配合gitee同步云设置

更换开发设备后&#xff0c;新安装的vscode软件&#xff0c;是没有原先的配置的&#xff0c;诸如快捷键&#xff0c;快捷代码段生成、安装的各个插件&#xff0c;插件的配置等都木大了&#xff0c;开发起来会很别扭&#xff0c;网上最多的就是去安装一个叫做Settings Sync的插件…

springcloud五大核心部件

springcloud五大核心部件 一、springcloud介绍 springcloud是微服务的集大成者&#xff0c;将一系列的组件进行了整合。基于springboot构建 &#xff0c;可以快速配置常用模块并构建庞大的分布式系统。 二、具体业务分析 我们举一个例子来进行业务场景分析 假设现在开发一…

Websocket学习

参考&#xff1a;http://www.mydlq.club/article/86/ 这里写目录标题一、WebSocket 简介二、WebSocket 特点三、为什么需要 WebSocket四、WebSocket 连接流程五、WebSocket 使用场景六、使用案例1.提醒客户端有新订单2.客户端交互一、WebSocket 简介 WebSocket 是一种基于 TCP…

为什么越来越多的企业在会议室使用无线流媒体网关?

1&#xff0c;用户已有华为&#xff0c;MAXHUB等投屏功能设备&#xff0c;不需要这个设备了。但是市面上大部分投屏设备的使用存在以下问题&#xff1a; 操作麻烦&#xff0c;我们发射器是直接触摸投屏&#xff0c;安全性低&#xff0c;需要驱动软件。 2&#xff0c;市场上有很…

实现矩阵连乘积(动态规划)

目录 实现矩阵连乘积 题目 问题分析 算法分析 时间复杂度 代码实现 执行结果 动态规划 基本思想 举例 个人主页&#xff1a;天寒雨落的博客_CSDN博客-初学者入门C语言,python,数据库领域博主 &#x1f4ac; 热门专栏&#xff1a;初学者入门C语言_天寒雨落的博客-CSDN…

【SVM分类】基于鸽群算法优化支持向量机SVM实现分类附matlab的代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

arduino 复习题

名词解释 中断 计算机运行过程中&#xff0c;出现某些意外情况需主机干预时&#xff0c;机器能自动停止正在运行的程序并转入处理新情况的程序&#xff0c;处理完毕后又返回原被暂停的程序继续运行 中断服务程序 用于 CPU 处理中断的程序 中断源 引起中断的原因&#xff0c;或…

【JVS低代码平台】如何实现与外部系统/内部代码直接对接?

JVS是开放性的低代码开发平台&#xff0c;为开发团队预留了多种对接的方式。我这里列举集中对接的模式。 用户对接&#xff08;统一登录/单点跳转&#xff09; 在日常的企业需求中&#xff0c;常常有这种情况。企业内部考勤打开都是通过钉钉或者企微的&#xff0c;那么希望我们…

Grasp Detection论文、代码汇总

文章目录2022End-to-end Trainable Deep Neural Network for Robotic Grasp Detection and Semantic Segmentation from RGB2019Antipodal Robotic Grasping using Generative Residual Convolutional Neural Network2022 End-to-end Trainable Deep Neural Network for Robot…

现代PCB生产工艺——加成法、减成法与半加成法

继续为朋友们分享关于PCB生产工艺的知识。 现代PCB生产工艺&#xff0c;目前主要分为&#xff1a;加成法、减成法与半加成法。 其具体定义如下&#xff1a; 加成法&#xff1a; 通过网印或曝光形成图形&#xff0c;经钻孔、沉铜、转移层压等工艺加工&#xff0c;直接将导电图形…

Pycharm开发环境下创建python运行的虚拟环境(自动执行安装依赖包)

问题&#xff1a;基于Django开发的后台程序涉及到很多依赖的开发包&#xff0c;将该项目迁移到其它电脑环境下运行需要搭建环境&#xff0c;由于项目中有requirement.txt&#xff0c;该文件内包含了运行该项目所需的依赖&#xff1b;最简便的方式是执行命令自动安装requirement…

postgresql11 主从配置详解

以下内容是针对pgsql11来做的。请看好版本再去考虑是否往下看 准备两台服务器&#xff0c;地址如下&#xff1a; 主&#xff1a;192.168.0.1pgsql11从:192.168.0.2pgsql11一、主库配置 1、创建具有复制权限的用户replica 密码为000000 CREATE ROLE replica login replicat…

Docker——数据卷命令

目录 一、数据卷 1.1 便于修改 1.2 数据共享 1.3 安全问题 1.4 数据卷的基本语法 二、 创建数据卷&#xff0c;并查看数据卷在宿主机的目录位置 2.1 创建数据卷 2.2 查看所有数据卷 2.3 查看数据卷详细信息卷 2.4 删除数据卷 三、挂载数据卷 3.1 创建容器并挂载数据卷…

智慧国土解决方案-最新全套文件

智慧国土解决方案-最新全套文件一、建设背景二、建设思路1、紧盯三大领域2、划分三个阶段3、面向三个维度三、建设方案轻应用微服务大平台应用设计四、获取 - 智慧国土全套最新解决方案合集一、建设背景 2019年5月9日&#xff0c;印发《关于建立国土空间规划体系并监督实施的若…

Pandas 数据中的loc与iloc含义以及操作

本节学习并记录pandas 的DataFrame类型的数据是怎么对列或者行进行操作的 1、df.loc: 语法格式是df.loc[<行表达式>, <列表达式>]&#xff0c;如果列不传将返回所有的行&#xff0c;loc操作通过索引和列的条件筛选出数据。 2、df.iloc: 语法格式是df.iloc[<行…

python初级学习

第一章 为什么要学习Python 那些最好的程序员不是为了得到更高的薪水或者得到公众的仰慕而编程,他们只是觉得这是-件有 趣的事情。 ——Linux 之父 Linus TorvaIds 作为-个实用主义的学习者,最关心的问题-定是「我为什么要选择学 Python, 学会之后我可以用来做什么&#xff1…

基于springboot电动车智能充电服务平台设计与实现的源码+文档

摘 要 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括电动车智能充电服务平台的网络应用&#xff0c;在外国电动车智能充电服务平台已经是很普遍的方式&#xff0c;不过国内的电动车智能充电服务平台可能还处于起步阶段。电…

Briefings in bioinformatics2022 | 基于神经网络的分子性质预测通用优化策略

原文标题&#xff1a;A general optimization protocol for molecular property prediction using a deep learning network 代码&#xff1a;GitHub - titanda/Learn-it-all at ready_classification_feature 一、问题提出 虽然个别优化方法都成功地提高了模型的性能&#…