Sharding-JDBC 数据库中间件

简介:Sharding-JDBC是一个开源的分布式数据库中间件,此处以2.x版本为目标讲解。

1. 特点

  A. Sharding-JDBC直接封装JDBC API,可适用于任何基于java的ORM框架(Mybatis/JPA),可基于任何第三方的数据库连接池(C3P0/Durid),理论上可支持任意实现JDBC规范的数据库(MySQL/Oracle);

  B. 功能方面:包括分库分表、读写分离、柔性事务、分布式主键和分布式治理;

  C. 配置多样化:支持Java编码和YAML的配置方式、支持自定义Spring命名空间与Spring boot starter;

  D. 性能方面:性能高,单库查询QPS为原生JDBC的99.8%,双库查询QPS比单库增加94%。

2. 核心概念

  A. 逻辑表(LogicTable):进行水平拆分的时候同一类型(逻辑、数据结构相同)的表的总称;

  B. 真实表(ActualTable):在分片的数据库中真实存在的物理表;

  C. 数据节点(DataNode):数据分片的最小单元,由数据源名称和真实表组成;

  D. 绑定表(BindingTable):指分片规则一致的主表和子表;

  E. 分片键(ShardingColumn):分片键用于将数据表水平拆分的字段,是指SQL语句中WHERE中的条件列;

  F. 分片算法(ShardingAlgorithm):进行水平拆分时采用的算法,分片算法需要应用方自行实现;

  G. 分片策略

    按策略类型分:

      StandardShardingStrategy(标准分片策略):只支持单分片键,提供PreciseShardingAlgorithm(精确分片算法,用于处理=和in的分片)和RangeShardingAlgorithm(范围分片算法,用于处理BETWEEN AND分片)两个分片算法;

      ComplexShardingStrategy(复合分片策略):支持多分片键,其余类似StandardShardingStrategy;

      InlineShardingStrategy(行表达式分片策略)

      HintShardingStrategy(Hint分片策略)

      NoneShardingStrategy(不分片策略)

    按策略配置分:

      数据源分片策略(DatabaseShardingStrategy):数据被分配的目标数据源;

      表分片策略(TableShardingStrategy):数据被分配的目标表,该目标表存在与该数据的目标数据源内;

      注意:如果分片规则中的所有表或大部分表的分片策略相同,可以使用默认策略来简化配置,如设置在ShardingRuleConfiguration类下,否则设置在TableRuleConfiguration类下。

3. Maven依赖

<!-- 引入sharding-jdbc核心模块(基于java和YAML配置) -->
<dependency>
    <groupId>io.shardingjdbc</groupId>
    <artifactId>sharding-jdbc-core</artifactId>
</dependency>
<!-- 引入sharding-jdbc核心模块(基于java和YAML配置) -->
<dependency>
  <groupId>io.shardingjdbc</groupId>
  <artifactId>sharding-jdbc-core-spring-namespace</artifactId>
</dependency>

4. 分库分表

  A. 基于java代码

复制代码
package com.ruhuanxingyun.sharding;

import java.util.Collection;

import com.ruhuanxingyun.sharding.datasource.DynamicDataSourceContextHolder;
import io.shardingjdbc.core.api.algorithm.sharding.PreciseShardingValue;
import io.shardingjdbc.core.api.algorithm.sharding.standard.PreciseShardingAlgorithm;

public class ModuloDatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
        Long databaseId = shardingValue.getValue();
        if (DynamicDataSourceContextHolder.containsDataSource("ds" + databaseId)) {
            return "ds" + databaseId;
        } else {
            return "ds1";
        }
    }
}
复制代码
复制代码
package com.ruhuanxingyun.sharding;

import io.shardingjdbc.core.api.config.TableRuleConfiguration;
import io.shardingjdbc.core.api.config.strategy.StandardShardingStrategyConfiguration;

public class ShardingJdbcConfiguration {
    
    public TableRuleConfiguration ruleConfig(String tableName, String nodes, String column) {
        // 配置表规则
        TableRuleConfiguration tableRuleConfig = new TableRuleConfiguration();
        tableRuleConfig.setLogicTable(tableName);
        tableRuleConfig.setActualDataNodes(nodes);
        tableRuleConfig.setKeyGeneratorColumnName(column);
        
         // 自定义的分片算法实现
        StandardShardingStrategyConfiguration standardStrategy = new StandardShardingStrategyConfiguration(column, ModuloDatabaseShardingAlgorithm.class.getName());
        // 配置分库策略
        tableRuleConfig.setDatabaseShardingStrategyConfig(standardStrategy);

        return tableRuleConfig;
    }

}
复制代码
复制代码
private DataSource buildShardingDataSource(Map<String, DataSource> dataSourceMap){
         // 配置分片规则
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        StringBuilder dbSb = new StringBuilder();
        if (dataSourceMap.size() != 0) {
            for (String str: dataSourceMap.keySet()) {
                dbSb.append(str+".user_info");
                dbSb.append(",");
            }
            String dbNodes = dbSb.toString().substring(0, dbSb.toString().length() - 1);
            shardingRuleConfig.getTableRuleConfigs().add(shardingJdbcConfiguration.ruleConfig(dbNodes, "user_info", "database_id"));

            // 默认设置db为ds1,也就是为那些没有配置分库分表策略的指定默认库
            shardingRuleConfig.setDefaultDataSourceName("ds1");
        }

        Properties properties = new Properties();
        properties.setProperty("sql.show", Boolean.FALSE.toString());

        DataSource dataSource = null;
        try {
            // 获取数据源对象
            dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, new ConcurrentHashMap(), properties);
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return dataSource;
    }
复制代码

  B. 基于yaml文件

5. 读写分离

  A. 基于java代码

  B. 基于yaml文件

复制代码
# 数据源配置,同分库分表
dataSources:
 # !!表示实现类 db_master:
!!com.alibaba.druid.pool.DruidDataSource name: master driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://172.17.0.1:3306/ruphie?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&useSSL=false username: ruhuanxingyun password: 123456 minIdle: 0 maxActive: 200 initialSize: 0 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 'x' validationQueryTimeout: 10000 testWhileIdle: true testOnBorrow: true testOnReturn: false maxWait: 60000 logAbandoned: true removeAbandoned: true removeAbandonedTimeout: 1800 db_slave: !!com.alibaba.druid.pool.DruidDataSource name: slave driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://172.17.0.2:3306/ruphie?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&useSSL=false username: ruhuanxingyun password: 123456 minIdle: 200 maxActive: 300 initialSize: 100 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 'x' validationQueryTimeout: 10000 testWhileIdle: true testOnBorrow: true testOnReturn: false maxWait: 60000 logAbandoned: true removeAbandoned: true removeAbandonedTimeout: 1800 masterSlaveRule:
 # 分库分表数据源名称 name: db_ms
 # master数据源名称 masterDataSourceName: db_master
# slave数据源名称,多个用数组表示[db_slave_0, db_slave_1] slaveDataSourceNames: db_slave
复制代码
复制代码
    @Value("${sharding-jdbc}")
    private Resource resourceFile;

    @Bean
    public DataSource dataSource() throws SQLException, IOException {
        byte[] bs = new byte[resourceFile.getInputStream().available()];
        resourceFile.getInputStream().read(bs);
        // 读写分离数据源构建方式
        return MasterSlaveDataSourceFactory.createDataSource(bs);
    }
复制代码

 6. SQL语句限制

  1. 不支持or/having/distinct关键字;

  2. 不支持多条语句insert和case when等。

 

可参考:shardingsphere官网地址

 

posted @   如幻行云  阅读(986)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示