SpringBoot集成Sharding-Jdbc分库分表

简介: ShardingSphere是一套开源分布式数据库中间件解决方案,包含Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar三款产品,提供数据分片、分布式事务和数据库治理功能,适用于多样化应用场景。

ShardingSphere实战分表分库

介绍

ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar这3款相互独立的产品组成。

他们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如Java同构、异构语言、云原生等各种多样化的应用场景。

垂直拆分

1.数据库拆分主要指分库分表,其目的主要是分散数据库压力,达到横向扩展,满足均衡访问等。

2.数据库拆分主要有两种方式:垂直拆分和水平拆分。

垂直拆分:

将不同业务功能相关的表放到不同的数据库中也就是类似于微服务架构中会员数据库/订单数据库/支付数据库

水平拆分

水平拆分:

当一张表的业务量行数如果超过500万行(阿里巴巴java开发手册官方推荐),分页/排序效率还是非常低,可以对同一张表数据实现拆分放到多个不同的表中存放。

如何分表分库

Mycat 与shadingjdbc 区别?

Mycat  是基于服务器端的形式实现数据库代理  基于服务器端的形式

改写sql语句

shadingjdbc  基于客户端 改写sql语句的形式实现实现数据库代理

基于客户端aop的机制改写sql语句。

shadingjdbc

Aop 代理  数据源

如果客户端发送jdbc语句 被aop代理改写sql语句

1. 基于服务器端mycat实现数据库代理

优点:能够保证数据库的安全性

缺点:效率比较低

2. 基于客户端Shardingjdbc实现数据库代理

优点:效率比较高

缺点:不能够保证数据库的安全性、客户端容易内存溢出

分表分库中间件

Mycat 基于服务器端  分表分库中间件

shadingjdbc 基于客户端改写sql  分表分库中间件

分表分库策略

分表分库需要考虑点:扩容性、每张表数据均匀性。

  1. 取余/取模 以后无法做扩容
  2. 按照范围分片   扩容性、每张表数据均匀性研究kafka的原理彻底明白
  3. 按照日期进行分片----订单表 -  order2021 order2022 order2023 订单号码
  4. 按照枚举值分片
  5. 二进制取模范围分片
  6. 一致性hash分片
  7. 按照目标字段前缀指定的进行分区
  8. 按照前缀ASCII码和值进行取模范围分片

Mysql集群环境搭建

安装master节点

关闭防火墙

systemctl stop firewalld

使用docker启动mysql 主节点

docker run --name mysql_master -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.13

参数说明:

mysql:5.7.13 指定运行的mysql版本

-d

以守护进程的方式启动

- -restart=always

docker重启时候容器自动重启

- -name

为容器指定名称,这里是master

-p

将容器的指定端口映射到主机的指定端口,这里是将容器的3306端口映射到主机的3306端口

创建从节点账号

连接主节点数据库上执行

GRANT REPLICATION SLAVE ON *.* to 'slave'@'%' identified by 'slave';
show grants for 'slave'@'%';

master节点配置

  1. 创建mysql配置文件目录
mkdir -p /usr/local/mysql/master
mkdir -p  /usr/local/mysql/slave

2. 将容器中的/etc/mysql/my.cnf 拷贝到容器外部

docker cp mysql_master:/etc/mysql/my.cnf /usr/local/mysql/master/my.cnf

将容器中/etc/mysql/my.cnf  拷贝容器外部中/usr/local/mysql/master/my.cnf

3. 进入外部cd  /usr/local/mysql/master

编辑 my.cnf

新增:

log-bin=mysql-bin ##使用binary logging,mysql-bin是log文件名的前缀
server-id=1 ###唯一服务器ID,非0整数,不能和其他服务器的server-id重复

4. 将修改后的文件覆盖DockerMySQL中的配置文件

docker cp /usr/local/mysql/master/my.cnf mysql_master:/etc/mysql/my.cnf

5 . 重启 mysql 的docker , 让配置生效

docker restart mysql_master

7. 查看主节点数据库是否开启binlog

show variables like 'log_bin';
show master status;

安装slave节点

关闭防火墙

systemctl stop firewalld

使用docker启动mysql slave节点

docker run --name mysql_slave -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.13

参数说明:

mysql:5.7.13 指定运行的mysql版本

-d

以守护进程的方式启动

- -restart=always

docker重启时候容器自动重启

- -name

为容器指定名称,这里是slave

-p

将容器的指定端口映射到主机的指定端口,这里是将容器的3306端口映射到主机的3306端口

slave节点配置

  1. 创建mysql配置文件目录
mkdir -p /usr/local/mysql/slave
mkdir -p  /usr/local/mysql/slave

2. 将容器中的/etc/mysql/my.cnf 拷贝到容器外部

docker cp mysql_slave:/etc/mysql/my.cnf /usr/local/mysql/slave/my.cnf

将容器中/etc/mysql/my.cnf  拷贝容器外部中/usr/local/mysql/slave/my.cnf

3. 进入外部:cd  /usr/local/mysql/slave

编辑 my.cnf

新增:

log-bin=mysql-bin ##使用binary logging,mysql-bin是log文件名的前缀
server-id=2 ###唯一服务器ID,非0整数,不能和其他服务器的server-id重复

4. 将修改后的文件覆盖DockerMySQL中的配置文件

docker cp /usr/local/mysql/slave/my.cnf mysql_slave:/etc/mysql/my.cnf

5 . 重启 mysql 的docker , 让配置生效

docker restart mysql_slave

查看从节点数据库bin_log 开启情况

show variables like 'log_bin';
STOP SLAVE;
CHANGE MASTER TO 
MASTER_HOST='连接Navicat的ip',
MASTER_PORT=正确的端口,
MASTER_USER='正确的用户名',
MASTER_PASSWORD='正确的密码';
START SLAVE;

my.conf 相关配置

[mysqld]
## 设置server_id,一般设置为IP,同一局域网内注意要唯一
server_id=100  
## 复制过滤:也就是指定哪个数据库不用同步(mysql库一般不同步)
binlog-ignore-db=mysql  
## 开启二进制日志功能,可以随便取,最好有含义(关键就是这里了)
log-bin=edu-mysql-bin  
## 为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存
binlog_cache_size=1M  
## 主从复制的格式(mixed,statement,row,默认格式是statement)
binlog_format=mixed  
## 二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。
expire_logs_days=7  
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062

SpringBoot项目整合Sharing-Jdbc

maven依赖

<properties>
  <sharding-sphere.version>4.1.1</sharding-sphere.version>
</properties>
<!-- for spring boot -->
<dependency>
  <groupId>org.apache.shardingsphere</groupId>
  <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
  <version>${sharding-sphere.version}</version>
</dependency>
<!-- for spring namespace -->
<dependency>
  <groupId>org.apache.shardingsphere</groupId>
  <artifactId>sharding-jdbc-spring-namespace</artifactId>
  <version>${sharding-sphere.version}</version>
</dependency>
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.2.6</version>
</dependency>

初始化测试数据库脚本

CREATE TABLE `sharing_user` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

数据库连接健康检查问题

解决SpringBoot2.6.6+,由于`sharding-jdbc`没有完全实现Datasouce接口规范导致功能不足。导致数据库连接健康检查不通过

/**
* @Author iron.guo
* @Date 2023/1/15
* @Description
*/
public class DataSourceConfig {
    @Bean
    public DataSourcePoolMetadataProvider getMetadata(DataSource encryptDataSource){
        return dataSource -> {
            if(dataSource instanceof EncryptDataSource && encryptDataSource instanceof EncryptDataSource ){
                return new ShardingSphereDruidDataSourcePoolMetadata((EncryptDataSource) encryptDataSource);
            }
            return null;
        };
    }
    public static class ShardingSphereDruidDataSourcePoolMetadata extends AbstractDataSourcePoolMetadata<EncryptDataSource> {
        private final DruidDataSource druidDataSource;
        protected ShardingSphereDruidDataSourcePoolMetadata(EncryptDataSource dataSource) {
            super(dataSource);
            this.druidDataSource = (DruidDataSource) dataSource.getDataSource();
        }
        @Override
        public Integer getActive() {
            return druidDataSource.getActiveCount();
        }
        @Override
        public Integer getMax() {
            return druidDataSource.getMaxActive();
        }
        @Override
        public Integer getMin() {
            return druidDataSource.getMinIdle();
        }
        @Override
        public String getValidationQuery() {
            return druidDataSource.getValidationQuery();
        }
        @Override
        public Boolean getDefaultAutoCommit() {
            return druidDataSource.isDefaultAutoCommit();
        }
    }
}

Sharing-Jdbc读写分离

设置sharing-jdbc读写分离配置

spring:
  main:
    # 允许Bean覆盖
    allow-bean-definition-overriding: true
  shardingsphere:
    datasource:
      names: master,slave                                   # 数据源名字
      master:
        driverClassName: com.mysql.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource        # 连接池
        url: jdbc:mysql://127.0.0.1:3306/sharing_db               # 主库地址
        username: root                                      # 主库用户名
        password: 123456                                    # 主库密码
      slave:
        driver-class-name: com.mysql.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource        # 连接池
        url: jdbc:mysql://127.0.0.1:3307/sharing_db    # 从库地址
        username: root
        password: 123456
    masterslave:
      load-balance-algorithm-type: round_robin              # 负载均衡算法,
      name: ms
      master-data-source-name: master                       # 主库数据源名字
      slave-data-source-names: slave                        # 从库数据源名字
    props:
      sql:
        show: true

测试接口

@GetMapping("writing")
    public ResponseResult<Boolean> writing(){
        User user=new User();
        user.setId(1);
        user.setName("iron");
        userService.save(user);
        return ResponseResult.Success();
    }
    @GetMapping("reading")
    public ResponseResult<?> reading(){
        User user = userService.getById(1);
        return ResponseResult.Success(user);
    }

访问读接口

访问写接口

Sharing-Jdbc分库分表

分表分库配置

spring:
  main:
    # 允许Bean覆盖
    allow-bean-definition-overriding: true
  shardingsphere:
    datasource:
      names: ds1,ds2                                   # 数据源名字
      ds1:
        driverClassName: com.mysql.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource        # 连接池
        url: jdbc:mysql://127.0.0.1:3306/sharing_db               # 主库地址
        username: root                                      # 主库用户名
        password: 123456                                    # 主库密码
      ds2:
        driver-class-name: com.mysql.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource        # 连接池
        url: jdbc:mysql://127.0.0.1:3307/sharing_db    # 从库地址
        username: root
        password: 123456
    sharding:
      default-data-source-name: ds1
      tables:
        sharing_user:
          key-generator:
            column: id
            type: SNOWFLAKE
          actual-data-nodes:  ds$->{1..1}.sharing_user$->{1..2}
          ## 自定义分表算法
          table-strategy:
            standard:
              precise-algorithm-class-name: com.tiger.sharingjdbc.config.TigerRangeShardingAlgorithm
              sharding-column: id
          # 分库策略:按id的奇偶性水平分片
          database-strategy:
            inline:
              sharding-column: id
              algorithm-expression: ds$->{id % 2 + 1}

分片算法实现

/**
 * @Author iron.guo
 * @Date 2023/1/15
 * @Description
 */
@Slf4j
public class TigerRangeShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
    private Long tableSize = 2L;
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<Long> preciseShardingValue) {
        Double userId = Double.valueOf(preciseShardingValue.getValue());
        Double temp = userId % tableSize +1;
        String tableName = "sharing_user" + (int)Math.ceil(temp);
        log.info("<tableName{}>", tableName);
        return tableName;
    }
}

调用接口他会分布存放在不同的表中

相关文章
|
存储 SQL 开发框架
SpringCloud微服务实战——搭建企业级开发框架(二十七):集成多数据源+Seata分布式事务+读写分离+分库分表
读写分离:为了确保数据库产品的稳定性,很多数据库拥有双机热备功能。也就是,第一台数据库服务器,是对外提供增删改业务的生产服务器;第二台数据库服务器,主要进行读的操作。   目前有多种方式实现读写分离,一种是Mycat这种数据库中间件,需要单独部署服务,通过配置来实现读写分离,不侵入到业务代码中;还有一种是dynamic-datasource/shardingsphere-jdbc这种,需要在业务代码引入jar包进行开发。
1302 26
SpringCloud微服务实战——搭建企业级开发框架(二十七):集成多数据源+Seata分布式事务+读写分离+分库分表
|
6月前
|
关系型数据库 MySQL 数据库
Springboot集成 Sharding-JDBC + Mybatis-Plus实现分库分表(源码)
Sharding-jdbc是开源的数据库操作中间件;定位为轻量级Java框架,在Java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
|
算法 Java 关系型数据库
springboot 2.0集成mycat 1.6 实现分库分表
springboot 2.0集成mycat 1.6 实现分库分表
836 0
springboot 2.0集成mycat 1.6 实现分库分表
|
11月前
|
Java Maven Docker
gitlab-ci 集成 k3s 部署spring boot 应用
gitlab-ci 集成 k3s 部署spring boot 应用
|
10月前
|
消息中间件 监控 Java
您是否已集成 Spring Boot 与 ActiveMQ?
您是否已集成 Spring Boot 与 ActiveMQ?
316 0
|
监控 druid Java
spring boot 集成配置阿里 Druid监控配置
spring boot 集成配置阿里 Druid监控配置
958 6
|
Java 关系型数据库 MySQL
如何实现Springboot+camunda+mysql的集成
【7月更文挑战第2天】集成Spring Boot、Camunda和MySQL的简要步骤: 1. 初始化Spring Boot项目,添加Camunda和MySQL驱动依赖。 2. 配置`application.properties`,包括数据库URL、用户名和密码。 3. 设置Camunda引擎属性,指定数据源。 4. 引入流程定义文件(如`.bpmn`)。 5. 创建服务处理流程操作,创建控制器接收请求。 6. Camunda自动在数据库创建表结构。 7. 启动应用,测试流程启动,如通过服务和控制器开始流程实例。 示例代码包括服务类启动流程实例及控制器接口。实际集成需按业务需求调整。
847 4
|
消息中间件 Java 测试技术
【RocketMQ系列八】SpringBoot集成RocketMQ-实现普通消息和事务消息
【RocketMQ系列八】SpringBoot集成RocketMQ-实现普通消息和事务消息
1017 1
|
消息中间件 Java Kafka
springboot集成kafka
springboot集成kafka
394 2

热门文章

最新文章