当前位置: 首页 > article >正文

SpringBoot整合sharding-jdbc 实现分库分表操作

1、简介

Sharding-JDBC 是一款开源的分布式数据库中间件,旨在简化分库分表(Sharding)的实现。它通过透明化的方式将数据分布到多个数据库或表中,同时提供与原生 JDBC 一致的开发体验。Sharding-JDBC 是 Apache ShardingSphere 项目的子模块之一,广泛应用于高并发、大数据量的场景。

核心功能
1、分库分表:

支持水平分库和水平分表,将数据分散到多个数据库或表中,提升系统性能和存储能力。

支持多种分片策略,如按范围、哈希、时间等。

2、读写分离:

支持主从架构的读写分离,将读操作路由到从库,写操作路由到主库,减轻主库压力。

3、分布式事务:

提供基于 XA 和柔性事务(Saga、TCC)的分布式事务支持,确保数据一致性。

4、数据脱敏:

支持对敏感数据进行加密和脱敏处理,保障数据安全。

5、多数据源管理:

支持动态数据源配置和管理,方便扩展和维护。

6、SQL 兼容性:

支持绝大多数 SQL 语法,兼容主流数据库(如 MySQL、PostgreSQL、Oracle 等)。

核心概念
1、逻辑表(Logic Table):

开发中使用的虚拟表名,例如 order。

2、真实表(Actual Table):

数据库中实际存在的表,例如 order_0、order_1。

3、数据节点(Data Node):

数据分片的最小单元,由数据源名称和真实表组成,例如 ds0.order_0。

4、分片键(Sharding Key):

用于分片的字段,例如订单表中的 user_id。

5、分片算法(Sharding Algorithm):

定义如何根据分片键将数据路由到不同的数据库或表。

6、绑定表(Binding Table):

具有相同分片规则的表,例如 order 和 order_item,可以避免跨表查询。

架构设计
Sharding-JDBC 采用轻量级的架构设计,直接嵌入应用程序中,无需额外部署中间件。其核心组件包括:

  • SQL 解析引擎:解析 SQL 语句,提取分片键。

  • 路由引擎:根据分片规则将 SQL 路由到正确的数据节点。

  • 改写引擎:将逻辑 SQL 改写为真实 SQL。

  • 执行引擎:执行 SQL 并合并结果。

使用场景
1、高并发场景:

通过分库分表提升系统的并发处理能力。

2、大数据量场景:

通过数据分片解决单表数据量过大的问题。

3、读写分离场景:

通过读写分离提升数据库的读性能。

4、多租户场景:

通过分库分表实现多租户数据隔离。

2、实战流程

2.1. pom.xml

<?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>

  <artifactId>spring-boot-demo-sharding-jdbc</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>spring-boot-demo-sharding-jdbc</name>
  <description>Demo project for Spring Boot</description>

  <parent>
    <groupId>com.xiaoma</groupId>
    <artifactId>spring-boot-demo</artifactId>
    <version>1.0.0-SNAPSHOT</version>
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <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-test</artifactId>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.1.0</version>
    </dependency>

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

    <dependency>
      <groupId>io.shardingsphere</groupId>
      <artifactId>sharding-jdbc-core</artifactId>
      <version>3.1.0</version>
    </dependency>

    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
    </dependency>

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

  <build>
    <finalName>spring-boot-demo-sharding-jdbc</finalName>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>

2.2. CustomSnowflakeKeyGenerator.java

package com.xiaoma.sharding.jdbc.config;

import cn.hutool.core.lang.Snowflake;
import io.shardingsphere.core.keygen.KeyGenerator;

public class CustomSnowflakeKeyGenerator implements KeyGenerator {
    private Snowflake snowflake;

    public CustomSnowflakeKeyGenerator(Snowflake snowflake) {
        this.snowflake = snowflake;
    }
    
    @Override
    public Number generateKey() {
        return snowflake.nextId();
    }
}

2.3. DataSourceShardingConfig.java

@Configuration
public class DataSourceShardingConfig {
    private static final Snowflake snowflake = IdUtil.createSnowflake(1, 1);

    /**
     * 需要手动配置事务管理器
     */
    @Bean
    public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "dataSource")
    @Primary
    public DataSource dataSource() throws SQLException {
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        // 设置分库策略
        shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "ds${user_id % 2}"));
        // 设置规则适配的表
        shardingRuleConfig.getBindingTableGroups().add("t_order");
        // 设置分表策略
        shardingRuleConfig.getTableRuleConfigs().add(orderTableRule());
        shardingRuleConfig.setDefaultDataSourceName("ds0");
        shardingRuleConfig.setDefaultTableShardingStrategyConfig(new NoneShardingStrategyConfiguration());

        Properties properties = new Properties();
        properties.setProperty("sql.show", "true");

        return ShardingDataSourceFactory.createDataSource(dataSourceMap(), shardingRuleConfig, new ConcurrentHashMap<>(16), properties);
    }

    private TableRuleConfiguration orderTableRule() {
        TableRuleConfiguration tableRule = new TableRuleConfiguration();
        // 设置逻辑表名
        tableRule.setLogicTable("t_order");
        // ds${0..1}.t_order_${0..2} 也可以写成 ds$->{0..1}.t_order_$->{0..1}
        tableRule.setActualDataNodes("ds${0..1}.t_order_${0..2}");
        tableRule.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "t_order_$->{order_id % 3}"));
        tableRule.setKeyGenerator(customKeyGenerator());
        tableRule.setKeyGeneratorColumnName("order_id");
        return tableRule;
    }

    private Map<String, DataSource> dataSourceMap() {
        Map<String, DataSource> dataSourceMap = new HashMap<>(16);

        // 配置第一个数据源
        HikariDataSource ds0 = new HikariDataSource();
        ds0.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds0.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test1?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8");
        ds0.setUsername("root");
        ds0.setPassword("root");

        // 配置第二个数据源
        HikariDataSource ds1 = new HikariDataSource();
        ds1.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds1.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8");
        ds1.setUsername("root");
        ds1.setPassword("root");

        dataSourceMap.put("ds0", ds0);
        dataSourceMap.put("ds1", ds1);
        return dataSourceMap;
    }

    /**
     * 自定义主键生成器
     */
    private KeyGenerator customKeyGenerator() {
        return new CustomSnowflakeKeyGenerator(snowflake);
    }

}

2.3. SpringBootDemoShardingJdbcApplicationTests.java

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootDemoShardingJdbcApplicationTests {
    @Autowired
    private OrderMapper orderMapper;

    /**
     * 测试新增
     */
    @Test
    public void testInsert() {
        for (long i = 1; i < 10; i++) {
            for (long j = 1; j < 20; j++) {
                Order order = Order.builder().userId(i).orderId(j).remark(RandomUtil.randomString(20)).build();
                orderMapper.insert(order);
            }
        }
    }

    /**
     * 测试更新
     */
    @Test
    public void testUpdate() {
        Order update = new Order();
        update.setRemark("修改备注信息");
        orderMapper.update(update, Wrappers.<Order>update().lambda().eq(Order::getOrderId, 2).eq(Order::getUserId, 2));
    }

    /**
     * 测试删除
     */
    @Test
    public void testDelete() {
        orderMapper.delete(new QueryWrapper<>());
    }

    /**
     * 测试查询
     */
    @Test
    public void testSelect() {
        List<Order> orders = orderMapper.selectList(Wrappers.<Order>query().lambda().in(Order::getOrderId, 1, 2));
        log.info("【orders】= {}", JSONUtil.toJsonStr(orders));
    }
    
}

http://www.kler.cn/a/562394.html

相关文章:

  • Android SDK封装打包流程详解
  • Flutter - 基础Widget
  • 如何优化频繁跳槽后的简历?
  • 华为hcia——Datacom实验指南——二层交换原理
  • 企业级服务器如何初始化数据磁盘
  • C#与AI的交互(以DeepSeek为例)
  • STM32 最小系统
  • ubuntu开机自动挂载硬盘
  • 获取GitHub的OAuth2的ClientId和ClientSecrets
  • nv docker image 下载与使用命令备忘
  • 《云豹录屏大师:免费解锁高清录屏新体验》
  • Kronecker分解(K-FAC):让自然梯度在深度学习中飞起来
  • matlab ylabel怎么让y轴显示的标签是正的
  • VMware虚拟机安装win10系统详细图文安装教程(附安装包) 2025最新版详细图文安装教程
  • 《炎龙骑士团 1 邪神之封印》游戏信息
  • 深搜专题2:组合问题
  • 易基因:RNA甲基化修饰和R-loop的交叉调控:从分子机制到临床意义|深度综述
  • 使用Python爬虫获取孔夫子旧书网已售商品数据:调用item_search_sold接口
  • SmartDV借助AI新动能以定制IP和生态合作推动AI SoC等全新智能芯片的研发及产业化
  • WordPress平台如何接入Deepseek,有效提升网站流量