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

Sharding-Proxy、ShardingSphere 和 Sharding-JDBC区别

在分库分表架构中,客户端解决方案和服务端解决方案的核心区别在于:分库分表的逻辑(如 “数据该路由到哪个分库 / 分表”)是在 “应用程序端” 实现,还是在 “独立的中间服务端” 实现。两者的架构、适用场景和优缺点有显著差异,以下是详细解析:

一、客户端分库分表解决方案

定义:分库分表的逻辑(数据路由、SQL 解析、结果合并等)嵌入在应用程序内部,与应用同进程运行,通过增强数据库驱动(如 JDBC)实现对分库分表的处理。

核心特点:

  1. 部署位置:与应用程序在同一个进程中(无独立服务),例如作为 Java 应用的一个 JAR 包依赖。
  2. 工作流程:
     
    应用程序 → 客户端分库分表组件(解析 SQL、计算路由) → 直接连接底层分库 / 分表 → 返回结果给应用。
  3. 典型代表:Sharding-JDBC、MyCat Client(轻量版)。

优点:

  • 性能损耗低:无网络转发开销(本地方法调用),适合高并发场景。
  • 部署简单:无需额外部署独立服务,随应用一起发布,运维成本低。
  • 响应速度快:减少 “应用→服务端代理→数据库” 的网络链路,延迟更低。

缺点:

  • 对应用有侵入性:需在应用中引入特定依赖(如 Sharding-JDBC 的 JAR 包),并配置分片规则。
  • 语言限制:通常只支持特定语言(如 Sharding-JDBC 仅支持 Java,因依赖 JDBC 规范)。
  • 配置分散:分片规则配置在应用中,若多个应用共用一套分库分表集群,需保证配置一致(否则会出现数据路由错误)。

适用场景:

  • 纯单一语言技术栈(如全 Java 微服务)。
  • 高并发、低延迟需求(如电商订单、支付系统)。
  • 应用团队与数据库团队协同紧密,可统一维护分片规则。

二、服务端分库分表解决方案

定义:分库分表的逻辑由独立部署的 “中间代理服务” 实现,应用程序通过数据库协议(如 MySQL 协议)连接代理,对分库分表无感知(像连接普通数据库一样)。

核心特点:

  1. 部署位置:作为独立服务进程部署(可集群化),与应用程序分离。
  2. 工作流程:
     
    应用程序 → 服务端代理(解析 SQL、计算路由、转发请求) → 底层分库 / 分表 → 代理合并结果 → 返回给应用。
  3. 典型代表:Sharding-Proxy、MyCat、DBProxy。

优点:

  • 应用无侵入:应用无需修改代码,仅需修改数据库连接地址(指向代理服务),适合遗留系统改造。
  • 语言无关:支持所有能连接数据库的语言(Java、Python、Go、PHP 等),适合多语言混合架构。
  • 配置集中管理:分片规则、权限控制等在代理服务中统一配置,避免多应用配置不一致。
  • 便于运维:可在代理层统一实现监控、审计、限流等功能,无需在每个应用中单独开发。

缺点:

  • 性能损耗较高:增加 “应用→代理→数据库” 的网络链路,存在网络延迟和代理服务的计算开销。
  • 部署复杂:需额外维护代理服务的集群(高可用、负载均衡),增加运维成本。
  • 代理成为瓶颈:若代理服务性能不足或出现故障,会影响所有连接它的应用。

适用场景:

  • 多语言混合架构(如 Java 微服务 + Python 数据分析 + Go 后台任务)。
  • 遗留系统分库分表改造(无法修改应用代码)。
  • 需集中管控分库分表规则(如运维团队统一管理)。
  • 对侵入性敏感的场景(如第三方系统接入分库分表集群)。

三、核心区别总结

对比维度客户端分库分表解决方案服务端分库分表解决方案
逻辑实现位置 应用程序内部(同进程) 独立代理服务(单独进程)
应用侵入性 有(需引入依赖、配置规则) 无(仅改连接地址)
语言支持 通常只支持特定语言(如 Java) 支持所有语言(基于数据库协议)
性能损耗 低(无网络转发) 中(网络转发 + 代理计算)
部署复杂度 简单(随应用部署) 复杂(需部署代理集群)
典型代表 Sharding-JDBC Sharding-Proxy、MyCat

四、选择建议

  • 优先选客户端方案:纯 Java 技术栈、高并发低延迟、应用可改造、追求性能。
  • 优先选服务端方案:多语言混合、应用不可改造(遗留系统)、需集中管理、对侵入性敏感。
实际场景中,两者也可混合使用(如 Java 应用用客户端方案,Python 应用用服务端方案连接同一套分库分表集群),灵活满足不同需求。

-------------------------------------------------------------------------------------------------------------------

Sharding-Proxy 和 Sharding-JDBC 都是 ShardingSphere 生态中用于分库分表的核心组件,但两者的 架构设计、接入方式、适用场景 有本质区别。以下从核心差异、功能对比、适用场景三个维度详细解析:

一、核心差异(架构层面)

维度Sharding-JDBCSharding-Proxy
定位 客户端分库分表解决方案(JDBC 驱动增强) 服务端分库分表解决方案(独立代理服务器)
接入方式 嵌入应用程序,作为 JDBC 驱动层组件存在 独立部署为代理服务,应用通过数据库协议(如 MySQL 协议)连接
对应用的侵入性 需在应用中引入依赖并配置,有一定侵入性 应用无感知,像连接普通数据库一样使用(仅需修改连接地址)
支持语言 仅支持 Java(基于 JDBC 规范) 支持所有语言(基于数据库协议,如 Java、Python、Go 等)
部署形式 与应用程序同进程部署(无独立进程) 独立进程部署(可集群化)
性能开销 无网络转发开销(本地方法调用),性能损耗极低 存在网络通信开销(应用 → 代理 → 数据库),性能损耗略高

二、功能与特性对比

1. 核心功能(分库分表能力)

两者核心功能一致,均支持:
  • 水平分表、垂直分表、水平分库、垂直分库
  • 多种分片策略(行表达式、哈希、范围、自定义等)
  • 读写分离、分布式事务(XA/BASE)
  • 数据加密、脱敏、SQL 审计

2. 差异化特性

特性Sharding-JDBCSharding-Proxy
配置管理 配置分散在各应用中(需通过注册中心实现集中管理) 配置集中在代理服务,支持动态更新(无需重启应用)
数据库协议支持 依赖 JDBC 驱动,支持所有兼容 JDBC 的数据库 支持 MySQL、PostgreSQL 等主流数据库协议(需适配)
连接池管理 由应用程序自身的连接池(如 HikariCP)管理 代理服务统一管理数据库连接池
监控与运维 需在应用层集成监控(如通过 Micrometer) 可通过代理层统一监控所有接入应用的分库分表行为
版本兼容性 与应用使用的 JDBC 版本强关联 与应用解耦,仅需兼容数据库协议版本

三、适用场景

1. 选择 Sharding-JDBC 的场景

  • 纯 Java 技术栈:如 Spring Boot/Cloud 应用,可直接集成 JDBC 驱动。
  • 高性能要求:无网络转发开销,适合高并发场景(如电商订单系统)。
  • 应用部署轻量化:无需额外部署代理服务,减少运维成本。
  • 灵活的配置更新:可通过应用配置中心(如 Nacos)动态更新分片规则。

2. 选择 Sharding-Proxy 的场景

  • 多语言混合架构:系统包含 Java、Python、Go 等多语言应用(如微服务 + 大数据组件)。
  • 应用无侵入需求:不希望修改应用代码(如遗留系统分库分表改造)。
  • 集中式管理:需要统一管控所有应用的分库分表规则、连接池、权限等(如运维团队统一管理)。
  • 非 Java 应用接入:如 Python 数据分析程序需要访问分库分表后的数据库。

四、总结:核心区别一句话概括

  • Sharding-JDBC 是「嵌入应用的客户端分库分表组件」,适合 Java 应用,追求高性能,需应用层集成。
  • Sharding-Proxy 是「独立部署的服务端代理」,适合多语言场景,应用无侵入,需额外维护代理服务。
实际场景中,两者可混合使用(如 Java 应用用 Sharding-JDBC,Python 应用用 Sharding-Proxy 连接同一套分库分表集群),共同构成 ShardingSphere 的分布式数据生态。

-------------------------------------------------------------------------------------------------------------------

Sharding-Proxy、Sharding-JDBC 是 ShardingSphere 生态中的两个核心组件,而 ShardingSphere 本身是一套完整的分布式数据库中间件解决方案。三者的关系和区别可以概括为:ShardingSphere 是 “生态”,Sharding-JDBC 和 Sharding-Proxy 是该生态中实现分库分表的 “具体工具”,但它们的架构和适用场景截然不同。

一、概念定义与关系

1. ShardingSphere(生态 / 平台)

ShardingSphere 是 Apache 开源的 分布式数据库中间件生态,旨在解决分布式场景下的数据分片、读写分离、分布式事务、数据安全等问题。它不是一个单一工具,而是包含多个组件的完整解决方案,核心组件包括:
  • Sharding-JDBC:客户端分库分表组件(嵌入应用)
  • Sharding-Proxy:服务端分库分表代理(独立部署)
  • Sharding-Sidecar:基于 Kubernetes 的云原生代理(较少用)
  • 其他辅助组件:如分布式事务组件(Atomikos/XA)、监控工具等
简单说:ShardingSphere 是 “总称”,Sharding-JDBC 和 Sharding-Proxy 是其实现分库分表的两种不同方式。

2. Sharding-JDBC(客户端组件)

Sharding-JDBC 是 ShardingSphere 的 客户端分库分表解决方案,它以 JDBC 驱动的形式嵌入到应用程序中,直接在应用层实现数据分片逻辑。
  • 本质:对 JDBC 接口的增强(如 DataSourceConnectionStatement 等),应用程序通过它直接操作底层数据库。
  • 特点:与应用同进程运行,无独立服务,性能损耗低。

3. Sharding-Proxy(服务端组件)

Sharding-Proxy 是 ShardingSphere 的 服务端分库分表解决方案,它以独立代理服务器的形式部署,应用程序通过数据库协议(如 MySQL 协议)连接代理,由代理完成数据分片逻辑。
  • 本质:一个 “中间代理层”,隔离了应用与底层数据库,应用无需感知分库分表细节。
  • 特点:独立进程运行,需单独部署,支持多语言接入。

二、核心区别对比

维度ShardingSphere(生态)Sharding-JDBC(客户端组件)Sharding-Proxy(服务端组件)
定位 分布式数据库中间件生态(包含多个组件) 客户端分库分表工具(嵌入应用) 服务端分库分表代理(独立部署)
形态 包含多个组件的平台 / 标准 Java 库(JAR 包),需嵌入应用 独立服务(可集群化部署)
接入方式 需选择具体组件(如 JDBC 或 Proxy) 应用引入依赖,配置分片规则,直接调用 JDBC 接口 应用通过数据库连接串连接代理(如 jdbc:mysql://proxy:3307/db
对应用的侵入性 取决于选择的组件 有侵入性(需修改应用依赖和配置) 无侵入性(应用无需修改代码,仅改连接地址)
支持语言 无限制(取决于组件) 仅支持 Java(基于 JDBC 规范) 支持所有语言(基于数据库协议,如 Java、Python、Go 等)
性能损耗 无(本身是生态) 极低(本地方法调用,无网络开销) 略高(应用→代理→数据库,存在网络转发)
适用场景 所有分布式数据库场景 纯 Java 应用、高并发场景(如电商订单) 多语言混合架构、遗留系统改造、需集中管理的场景

三、功能覆盖范围

三者在核心功能上的关系:
  • ShardingSphere 生态的所有功能(如分片、读写分离、事务),Sharding-JDBC 和 Sharding-Proxy 均支持(功能上基本一致)。
  • 差异主要体现在 架构设计和接入方式,而非功能本身。

四、如何选择?

  1. 纯 Java 技术栈 + 高性能需求:选 Sharding-JDBC(无网络开销,适合高并发)。
  2. 多语言混合架构(如 Java + Python):选 Sharding-Proxy(支持跨语言)。
  3. 遗留系统改造(不想改代码):选 Sharding-Proxy(应用无侵入)。
  4. 需要集中管理分片规则:选 Sharding-Proxy(配置集中在代理,方便运维)。

总结

  • ShardingSphere 是 “生态”,定义了分布式数据库的标准和解决方案。
  • Sharding-JDBC 和 Sharding-Proxy 是该生态中实现分库分表的 “两种工具”:前者是 “客户端嵌入型”,后者是 “服务端代理型”。
  • 两者互补共存,可根据技术栈、性能需求、运维模式选择,甚至在同一系统中混合使用(如 Java 应用用 JDBC,Python 应用用 Proxy 连接同一套分库分表集群)。

-------------------------------------------------------------------------------------------------------------------

在 Spring Boot 项目中,分库分表是解决海量数据存储与查询性能问题的核心方案。目前主流的分库分表技术可分为 客户端集成方案、服务端代理方案 和 云原生方案,每种方案有其适配场景和集成方式。以下是 Spring Boot 常用分库分表技术的总结:

一、客户端集成方案(推荐纯 Java 技术栈)

客户端方案的核心是 在应用内部嵌入分库分表逻辑,通过增强 JDBC 驱动实现数据路由,与 Spring Boot 集成紧密,性能损耗低。

1. Sharding-JDBC(Apache ShardingSphere)

简介:ShardingSphere 生态的核心组件,轻量级客户端分库分表工具,以 JDBC 驱动形式嵌入应用,无需独立部署。核心功能:
  • 支持水平分表、水平分库、垂直分表、垂直分库
  • 内置多种分片策略(哈希、范围、行表达式、自定义等)
  • 支持读写分离、分布式事务(XA/BASE)、数据加密
  • 兼容 Spring Boot 自动配置,无缝集成
Spring Boot 集成方式:
  1. 引入 Starter 依赖:
    xml
     
     
    <dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId><version>5.3.2</version>
    </dependency>
    
     
     
  2. 配置分片规则(application.yml):
    yaml
     
     
    spring:shardingsphere:datasource:names: db0,db1  # 分库名称db0:  # 数据库0配置type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/db0username: rootpassword: rootdb1:  # 数据库1配置(同db0)rules:sharding:tables:t_order:  # 订单表分片规则actual-data-nodes: db${0..1}.t_order${0..1}  # 实际分表:db0.t_order0, db0.t_order1, db1.t_order0, db1.t_order1database-strategy:  # 分库策略(按用户ID哈希)standard:sharding-column: user_idsharding-algorithm-name: order_db_inlinetable-strategy:  # 分表策略(按订单ID哈希)standard:sharding-column: order_idsharding-algorithm-name: order_table_inlinesharding-algorithms:order_db_inline:  # 分库算法(行表达式)type: INLINEprops:algorithm-expression: db${user_id % 2}order_table_inline:  # 分表算法type: INLINEprops:algorithm-expression: t_order${order_id % 2}
    
     
     
优点:
  • 性能优异(无网络开销,本地方法调用),适合高并发场景
  • 与 Spring Boot 无缝集成,配置简单
  • 支持动态调整分片规则(结合配置中心)
缺点:
  • 仅支持 Java 语言(依赖 JDBC 规范)
  • 需在应用中配置分片规则,对应用有一定侵入性
适用场景:纯 Java 技术栈、高并发业务(如电商订单、支付系统)、中小规模分库分表(分库分表数 ≤ 100)。

2. Dynamic Datasource + 自定义分片

简介:基于动态数据源框架(如 dynamic-datasource-spring-boot-starter),手动实现简单分片逻辑,适合规则简单的场景。核心思路:
  • 用动态数据源切换不同分库
  • 在 SQL 执行前拦截并修改表名(如 t_order → t_order_001
Spring Boot 集成方式:
  1. 引入动态数据源依赖:
    xml
     
     
    <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.2</version>
    </dependency>
    
     
     
  2. 配置多数据源并自定义分片逻辑:
    java
     
    运行
     
     
     
     
    // 分片工具类(按用户ID路由分库分表)
    public class ShardingUtils {public static String getDbName(Long userId) {return "db" + (userId % 2); // 分2个库}public static String getTableName(String baseTable, Long orderId) {return baseTable + "_" + (orderId % 4); // 分4个表}
    }// 业务层使用
    @Service
    public class OrderService {@Autowiredprivate JdbcTemplate jdbcTemplate;public void saveOrder(Order order) {// 1. 切换分库DynamicDataSourceContextHolder.push(ShardingUtils.getDbName(order.getUserId()));// 2. 生成分表名String tableName = ShardingUtils.getTableName("t_order", order.getOrderId());// 3. 执行SQLjdbcTemplate.update("insert into " + tableName + "(...) values(...)", ...);// 4. 清除数据源上下文DynamicDataSourceContextHolder.poll();}
    }
    
     
     
优点:实现简单,灵活度高,适合规则简单的场景(如按单一字段哈希分片)。缺点:需手动处理分片逻辑,不支持复杂 SQL(如跨表联合查询),无分布式事务支持。适用场景:中小规模数据、分片规则简单(如仅水平分表)、快速迭代的业务。

二、服务端代理方案(推荐多语言 / 无侵入场景)

服务端方案通过 独立部署的代理服务 实现分库分表逻辑,应用只需连接代理(如连接普通数据库),对应用无侵入,支持多语言。

1. Sharding-Proxy(Apache ShardingSphere)

简介:ShardingSphere 生态的服务端代理组件,独立部署为中间件,支持 MySQL、PostgreSQL 等协议,应用通过数据库连接串访问。核心功能:与 Sharding-JDBC 功能一致(分片、读写分离、事务等),但架构不同(服务端代理)。
Spring Boot 集成方式:
  1. 部署 Sharding-Proxy 服务(独立进程),配置分片规则(conf/server.yaml 和 conf/config-sharding.yaml)。
  2. Spring Boot 应用直接连接代理,无需引入额外依赖:
    yaml
     
     
    spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://sharding-proxy:3307/order_db  # 连接代理地址username: rootpassword: root
    
     
     
优点:
  • 应用无侵入(仅改连接地址),支持多语言(Java、Python、Go 等)
  • 分片规则集中管理,适合多应用共用一套分库分表集群
  • 便于统一运维(监控、审计、限流)
缺点:
  • 存在网络开销(应用→代理→数据库),性能略低于 Sharding-JDBC
  • 需额外部署代理集群(保证高可用),增加运维成本
适用场景:多语言混合架构、遗留系统改造(无法修改应用代码)、需集中管理的大规模分库分表。

2. MyCat

简介:国内开源的分布式数据库中间件,基于服务端代理模式,支持 MySQL、Oracle 等数据库,功能全面但配置较复杂。核心功能:分库分表、读写分离、全局序列号、分布式事务(弱支持)。
Spring Boot 集成方式:
  1. 部署 MyCat 服务,配置 schema.xml(逻辑库表映射)、rule.xml(分片规则)。
  2. 应用连接 MyCat 代理(同连接普通 MySQL):
    yaml
     
     
    spring:datasource:url: jdbc:mysql://mycat-server:8066/order_schema  # MyCat 逻辑库username: rootpassword: 123456
    
     
     
优点:支持复杂场景(如跨库 Join、全局表),生态成熟,适合传统企业级应用。缺点:配置复杂,性能损耗高于 Sharding-Proxy,社区活跃度略低。适用场景:传统企业级应用、复杂分库分表规则(如多维度分片)、遗留系统迁移。

三、云原生方案(推荐容器化 / 云环境)

随着云原生普及,基于 Kubernetes 的分库分表方案逐渐兴起,适合容器化部署的微服务架构。

ShardingSphere-Operator(云原生部署)

简介:ShardingSphere 提供的 Kubernetes Operator,可在 K8s 中快速部署和管理 Sharding-JDBC/Proxy 集群,支持动态扩缩容、配置自动更新。核心优势:
  • 与 K8s 生态深度集成(ConfigMap 管理配置、Service 暴露服务)
  • 支持分片集群的自动扩缩容(如新增分库时自动更新规则)
  • 适合大规模、动态变化的云原生场景
适用场景:容器化部署的微服务、大规模分库分表(分库分表数 ≥ 100)、需要动态扩缩容的业务。

四、技术选择建议

场景需求推荐技术核心原因
纯 Java 技术栈 + 高并发 Sharding-JDBC 性能优异,与 Spring Boot 无缝集成
多语言混合架构 Sharding-Proxy 应用无侵入,支持跨语言
遗留系统改造(无代码修改) MyCat / Sharding-Proxy 仅改连接地址,零侵入
分片规则简单(中小数据) Dynamic Datasource 自定义 实现简单,灵活度高
云原生 / 容器化部署 ShardingSphere-Operator 适配 K8s 生态,支持动态扩缩容

总结

Spring Boot 分库分表技术的选择核心是 “权衡性能、侵入性、运维成本”:
  • 追求性能和 Java 生态适配:优先 Sharding-JDBC
  • 需多语言支持或无侵入:优先 Sharding-Proxy
  • 复杂企业级场景:可考虑 MyCat
  • 云原生环境:首选 ShardingSphere-Operator
实际落地时,建议结合业务数据量(单表 ≥ 1000 万行再考虑分表)、增长速度和团队技术栈综合决策。

-------------------------------------------------------------------------------------------------------------------

springboot+分库分表架构设计
 
在 Spring Boot 项目中设计分库分表架构,需结合业务场景(数据量、访问模式)、性能需求和扩展性要求,从 数据分片策略、技术选型、核心组件设计、高可用保障 等维度系统规划。以下是一套可落地的架构设计方案:

一、架构设计目标

  1. 解决海量数据问题:单表数据量超过 1000 万行时,通过分库分表降低单库 / 单表压力。
  2. 提升查询性能:减少单库 / 单表的 IO 和锁竞争,优化查询响应速度(目标:90% 查询 < 100ms)。
  3. 支持水平扩展:可通过新增数据库节点快速扩容,无需重构核心架构。
  4. 保证数据一致性:在分布式场景下,确保分库分表后的事务完整性和数据准确性。
  5. 业务无感知:通过中间件封装分库分表逻辑,减少对业务代码的侵入。

二、核心架构选型

1. 分库分表中间件

推荐 Sharding-JDBC(客户端方案),理由:
  • 与 Spring Boot 无缝集成,适配 Java 生态。
  • 无独立服务开销,性能损耗低(本地方法调用)。
  • 支持动态分片规则(结合 Nacos 配置中心实时更新)。
  • 兼容 Spring Data JPA/MyBatis 等 ORM 框架。
备选方案:若存在多语言服务(如 Python 数据分析),可搭配 Sharding-Proxy(服务端代理)作为补充。

2. 数据存储层

  • 主数据库:MySQL 8.0(支持原生分表、CTE 等特性,适配 ShardingSphere)。
  • 从数据库:与主库一致,用于读写分离(减轻主库查询压力)。
  • 存储引擎:InnoDB(支持事务和行级锁,适合高并发写入)。

3. 配套中间件

  • 配置中心:Nacos(存储分片规则、数据源配置,支持动态更新)。
  • 分布式事务:Seata(解决跨库事务问题,支持 AT 模式(自动补偿))。
  • 全局 ID 生成:Snowflake 算法(保证分库分表后 ID 全局唯一)。
  • 监控告警:Prometheus + Grafana(监控分库分表性能、数据源负载)。

三、数据分片策略设计

1. 分片维度选择

根据业务场景选择 水平分表、水平分库 或 垂直分库 / 分表:
分片类型适用场景示例
水平分表 单表数据量大,但访问频率低(如历史订单) t_order → t_order_00~t_order_15
水平分库 单库压力大(高并发读写),需分摊存储 / 计算 按用户 ID 哈希分为 db_user_0~db_user_3
垂直分库 业务模块耦合低,可按业务拆分(如用户、订单) 订单库 db_order、用户库 db_user
垂直分表 表字段过多,冷热数据分离(如大字段拆分) t_user → t_user_base(基础信息)+ t_user_ext(扩展信息)

2. 分片键设计(核心)

分片键的选择直接影响查询效率,需满足:
  • 高频查询字段:确保多数查询能通过分片键路由到单一分库 / 分表(避免全库扫描)。
  • 分布均匀性:避免数据倾斜(如某分表数据量是其他的 10 倍以上)。
示例场景:
  • 订单表(t_order):
    • 分库键:user_id(用户 ID,确保同一用户的订单在同一库,便于查询用户所有订单)。
    • 分表键:order_id(订单 ID,按哈希分表,均匀分布数据)。
  • 商品表(t_product):
    • 分表键:category_id(分类 ID,同类商品集中存储,适合分类查询)。

3. 分片算法选择

算法类型适用场景示例
哈希分片 分片键为数字 / 字符串,需均匀分布 user_id % 4 → 分为 4 个库
范围分片 分片键为时间 / 自增 ID,需按区间查询 按月份分表:t_order_202401t_order_202402
枚举分片 分片键值有限且固定(如地区、状态) 按地区分库:db_shanghaidb_beijing
自定义分片 复杂业务规则(如多字段组合分片) 按 user_id % 2 + order_time 混合分片

4. 全局 ID 生成策略

分库分表后需避免 ID 冲突,推荐 Snowflake 算法:
  • 结构:1 位符号位 + 41 位时间戳 + 10 位机器 ID + 12 位序列号(支持单节点每秒生成 4096 个 ID)。
  • 集成方式:通过 ShardingSphere 内置 SNOWFLAKE 算法,或接入分布式 ID 服务(如 Leaf)。
yaml
 
 
# Sharding-JDBC 全局 ID 配置
spring:shardingsphere:rules:sharding:key-generators:snowflake:type: SNOWFLAKEprops:worker-id: 1  # 机器 ID(集群部署需唯一)
 

四、核心架构组件设计

1. 数据源管理层

通过 Sharding-JDBC 管理多数据源,动态路由分库 / 分表:
yaml
 
 
# application.yml 数据源配置(Nacos 中管理)
spring:shardingsphere:datasource:names: db0,db1,db2,db3  # 4 个分库db0:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://db0:3306/db_order_0username: ${DB_USERNAME}password: ${DB_PASSWORD}# db1/db2/db3 配置同上(略)rules:sharding:tables:t_order:  # 订单表分片规则actual-data-nodes: db${0..3}.t_order${0..7}  # 4 库 × 8 表 = 32 个分表database-strategy:  # 分库策略(user_id 哈希)standard:sharding-column: user_idsharding-algorithm-name: order_db_inlinetable-strategy:  # 分表策略(order_id 哈希)standard:sharding-column: order_idsharding-algorithm-name: order_table_inlinekey-generate-strategy:  # 全局 ID 生成column: order_idkey-generator-name: snowflakesharding-algorithms:order_db_inline:type: INLINEprops:algorithm-expression: db${user_id % 4}  # 4 个分库order_table_inline:type: INLINEprops:algorithm-expression: t_order${order_id % 8}  # 每个库 8 个分表
 

2. 业务接入层

通过 Spring Boot 整合 MyBatis/MyBatis-Plus,业务代码无需感知分库分表逻辑:
java
 
运行
 
 
 
 
// 实体类(与逻辑表名一致)
@Data
@TableName("t_order")  // 逻辑表名,Sharding-JDBC 自动路由到分表
public class Order {private Long orderId;  // 全局 ID(Snowflake 生成)private Long userId;   // 分库键private BigDecimal amount;private LocalDateTime createTime;
}// Mapper 层(正常编写 SQL,无需关心分表)
public interface OrderMapper extends BaseMapper<Order> {// 按 user_id 查询(自动路由到对应分库)List<Order> selectByUserId(@Param("userId") Long userId);// 按 order_id 查询(自动路由到对应分表)Order selectByOrderId(@Param("orderId") Long orderId);
}// 服务层(正常调用,Sharding-JDBC 自动处理路由)
@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;public void createOrder(Order order) {orderMapper.insert(order);  // 自动路由到 db${user_id%4}.t_order${order_id%8}}public List<Order> getOrdersByUserId(Long userId) {return orderMapper.selectByUserId(userId);  // 仅查询用户所在分库的分表}
}
 

3. 分布式事务处理

跨库操作时(如创建订单同时扣减库存),通过 Seata 保证事务一致性:
  1. 引入 Seata 依赖:
xml
 
 
<dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>1.6.1</version>
</dependency>
 
  1. 配置 Seata(注册到 Nacos):
yaml
 
 
seata:tx-service-group: my_test_tx_group  # 事务分组service:vgroup-mapping:my_test_tx_group: defaultgrouplist:default: seata-server:8091registry:type: nacosnacos:server-addr: nacos:8848group: SEATA_GROUP
 
  1. 业务层添加 @GlobalTransactional 注解:
java
 
运行
 
 
 
 
@Service
public class OrderTransactionService {@Autowiredprivate OrderService orderService;@Autowiredprivate InventoryService inventoryService;  // 库存服务(可能在另一分库)@GlobalTransactional  // 分布式事务注解public void createOrderWithInventory(Order order, Long productId, Integer quantity) {// 1. 创建订单(分库 A)orderService.createOrder(order);// 2. 扣减库存(分库 B)inventoryService.deduct(productId, quantity);// 若步骤 2 失败,步骤 1 会自动回滚}
}
 

4. 读写分离设计

通过 Sharding-JDBC 配置主从复制,将查询请求路由到从库:
yaml
 
 
spring:shardingsphere:rules:readwrite-splitting:data-sources:order-db-group:  # 主从分组type: Staticprops:write-data-source-name: db0  # 主库(写入)read-data-source-names: db0-slave1,db0-slave2  # 从库(读取)load-balancer-name: round_robin  # 负载均衡策略(轮询)load-balancers:round_robin:type: ROUND_ROBIN  # 轮询策略
 

五、部署与高可用设计

1. 部署架构

  • 应用层:Spring Boot 应用集群(多实例部署,通过 Nginx 负载均衡)。
  • 数据层:
    • 主库:一主多从(主库写入,从库同步数据并承担查询)。
    • 分库集群:按分片规则部署多个数据库节点(如 4 个分库,每个分库 1 主 2 从)。
  • 中间件:
    • Sharding-JDBC:嵌入应用内部(无独立部署)。
    • Seata/ Nacos:集群部署(保证高可用)。

2. 扩容策略

当数据量增长超过当前分片容量时,通过 翻倍扩容 避免数据迁移复杂度:
  • 例:从 4 个分库扩容到 8 个分库,新分片规则为 user_id % 8,原分库数据按 user_id % 4 迁移到新分库(如原 db0 数据迁移到新 db0 和 db4)。
  • 扩容过程:通过 ShardingSphere 动态更新分片规则(无需停服),配合双写工具同步新旧分片数据。

六、监控与运维

  1. 性能监控:
    • 接入 Prometheus 采集 Sharding-JDBC 指标(如分库查询耗时、路由成功率)。
    • Grafana 配置看板,监控分库 / 分表的 QPS、延迟、连接数。
  2. 日志追踪:
    • 集成 SkyWalking 跟踪分布式 SQL 执行链路(从应用到分库分表的完整路径)。
    • 记录分片路由日志(shardingsphere.sql 日志级别设为 INFO)。
  3. 配置管理:
    • 所有分片规则、数据源配置存储在 Nacos,支持动态更新(无需重启应用)。
    • 配置变更需通过审批流程,避免误操作导致数据路由错误。

七、注意事项与优化

  1. 避免跨库查询:设计时尽量通过分片键确保查询落在单一分库 / 分表,跨库 Join 需谨慎使用(可通过全局表、广播表优化)。
  2. 索引优化:分表后索引仅对当前分表有效,需保证分片键和查询字段均有索引。
  3. 历史数据归档:对超过保留期的数据(如 1 年前的订单),迁移到冷存储(如阿里云 OSS + 表格存储)。
  4. 压测验证:上线前通过 JMeter 模拟高并发场景,验证分库分表后的性能瓶颈(如单分表 QPS 是否满足需求)。

总结

Spring Boot + 分库分表架构的核心是 “以业务为中心的分片策略 + 低侵入的中间件集成 + 可扩展的部署设计”。通过 Sharding-JDBC 实现客户端分片,结合 Nacos 动态配置、Seata 分布式事务,可构建一套高性能、高可用的海量数据处理方案。实际落地时需根据数据量增长速度、查询模式持续优化分片规则,避免过度设计。

-------------------------------------------------------------------------------------------------------------------

下面我将详细介绍 Spring Boot 集成 ShardingSphere 的代码配置,包括分库分表、读写分离、全局 ID 生成等核心功能的实现。

我们将使用 ShardingSphere-JDBC 5.x 版本,这是目前的稳定版本,提供了丰富的功能和良好的 Spring Boot 集成支持。
 
 
Spring Boot 集成 ShardingSphere 详细配置
V1
创建时间:14:55

配置说明

以上配置实现了一个完整的 Spring Boot + ShardingSphere 分库分表方案,主要包含以下核心功能:
  1. 数据源配置:
    • 配置了 2 个主库(master0, master1)和 2 个从库(slave0, slave1)
    • 使用 HikariCP 连接池管理数据库连接
  2. 读写分离:
    • 配置了两个主从分组(order-db-group-0, order-db-group-1)
    • 写操作路由到主库,读操作路由到从库
    • 支持轮询和权重两种负载均衡策略
  3. 分库分表:
    • 按 userId 进行分库(2 个库)
    • 按 orderId 进行分表(每个库 4 个表)
    • 实际数据节点为:order-db-group-0.t_order_0 到 order-db-group-1.t_order_3
  4. 全局 ID 生成:
    • 使用雪花算法(Snowflake)生成全局唯一的 orderId
    • 避免了分库分表环境下的 ID 冲突问题

代码结构说明

  1. 实体类(Order.java):
    • 使用逻辑表名 t_order
    • 主键字段使用 MyBatis-Plus 的 @TableId 注解
  2. 数据访问层(OrderMapper.java):
    • 继承 MyBatis-Plus 的 BaseMapper 接口
    • 定义了按 userId 和 orderId 查询的方法
    • SQL 语句中使用逻辑表名,ShardingSphere 会自动路由到实际分表
  3. 服务层(OrderService.java):
    • 业务代码完全不需要关心分库分表逻辑
    • 正常使用 MyBatis-Plus 提供的 CRUD 方法
    • 支持事务管理
  4. 控制器层(OrderController.java):
    • 提供 RESTful API 接口
    • 接收前端请求并调用服务层处理

动态配置(可选)

如果需要动态调整分片规则,可以集成 Nacos 配置中心:
  1. 添加 Nacos 配置依赖(已在 pom.xml 中包含)
  2. 创建 bootstrap.yml 配置文件指定 Nacos 地址
  3. 将 ShardingSphere 配置迁移到 Nacos 配置中心
  4. 配置变更时,ShardingSphere 会自动感知并更新规则

注意事项

  1. SQL 限制:
    • 避免使用复杂的跨库 JOIN 操作
    • 分页查询需要注意使用分片键,否则可能导致结果不准确
    • 不支持某些聚合函数的跨库计算
  2. 事务管理:
    • 单库事务可以直接使用 Spring 的 @Transactional 注解
    • 跨库事务需要集成 Seata 等分布式事务框架
  3. 性能优化:
    • 合理设计分片键,避免数据倾斜
    • 为分片键和查询频繁的字段建立索引
    • 生产环境关闭 SQL 日志输出(sql-show: false
  4. 监控与运维:
    • 集成 ShardingSphere 的监控功能
    • 定期检查各分库分表的数据分布情况
    • 制定数据归档和清理策略
通过以上配置,你可以在 Spring Boot 项目中快速实现分库分表功能,有效解决海量数据存储和查询性能问题。
 
package com.example.shardingspheredemo.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.math.BigDecimal;
import java.time.LocalDateTime;/*** 订单实体类* 注意:表名是逻辑表名,实际分表由ShardingSphere管理*/
@Data
@TableName("t_order")  // 逻辑表名
public class Order {/*** 订单ID,使用ShardingSphere的雪花算法生成*/@TableId(type = IdType.AUTO)  // 这里AUTO是假象,实际由ShardingSphere的key-generator生成private Long orderId;/*** 用户ID,用于分库*/private Long userId;/*** 订单金额*/private BigDecimal amount;/*** 订单状态*/private Integer status;/*** 创建时间*/private LocalDateTime createTime;/*** 更新时间*/private LocalDateTime updateTime;
}

  

package com.example.shardingspheredemo.controller;import com.example.shardingspheredemo.entity.Order;
import com.example.shardingspheredemo.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;/*** 订单控制器*/
@RestController
@RequestMapping("/orders")
public class OrderController {@Autowiredprivate OrderService orderService;/*** 创建订单*/@PostMappingpublic Long createOrder(@RequestParam Long userId) {return orderService.createOrder(userId);}/*** 批量创建订单*/@PostMapping("/batch")public String batchCreateOrders(@RequestParam Long userId, @RequestParam int count) {orderService.batchCreateOrders(userId, count);return "Successfully created " + count + " orders";}/*** 根据用户ID查询订单*/@GetMapping("/user/{userId}")public List<Order> getOrdersByUserId(@PathVariable Long userId) {return orderService.getOrdersByUserId(userId);}/*** 根据订单ID查询订单*/@GetMapping("/{orderId}")public Order getOrderByOrderId(@PathVariable Long orderId) {return orderService.getOrderByOrderId(orderId);}
}

  

package com.example.shardingspheredemo.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.shardingspheredemo.entity.Order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;/*** 订单Mapper接口* 注意:SQL中使用的是逻辑表名t_order,ShardingSphere会自动路由到实际分表*/
@Mapper
public interface OrderMapper extends BaseMapper<Order> {/*** 根据用户ID查询订单列表* 会被路由到该用户ID对应的分库*/List<Order> selectByUserId(@Param("userId") Long userId);/*** 根据订单ID查询订单* 会被路由到该订单ID对应的分库分表*/Order selectByOrderId(@Param("orderId") Long orderId);/*** 批量插入订单*/int batchInsert(@Param("orders") List<Order> orders);
}

  

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- 注意:这里使用的是逻辑表名t_order -->
<mapper namespace="com.example.shardingspheredemo.mapper.OrderMapper"><!-- 根据用户ID查询订单 --><select id="selectByUserId" resultType="com.example.shardingspheredemo.entity.Order">SELECT * FROM t_order WHERE user_id = #{userId} ORDER BY create_time DESC</select><!-- 根据订单ID查询订单 --><select id="selectByOrderId" resultType="com.example.shardingspheredemo.entity.Order">SELECT * FROM t_order WHERE order_id = #{orderId}</select><!-- 批量插入订单 --><insert id="batchInsert">INSERT INTO t_order (user_id, amount, status, create_time, update_time)VALUES<foreach collection="orders" item="order" separator=",">(#{order.userId}, #{order.amount}, #{order.status}, #{order.createTime}, #{order.updateTime})</foreach></insert>
</mapper>

  

package com.example.shardingspheredemo.service;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.shardingspheredemo.entity.Order;
import com.example.shardingspheredemo.mapper.OrderMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;/*** 订单服务实现类* 业务代码中无需关心分库分表逻辑,ShardingSphere会自动处理*/
@Service
public class OrderService extends ServiceImpl<OrderMapper, Order> {/*** 创建订单*/@Transactionalpublic Long createOrder(Long userId) {Order order = new Order();order.setUserId(userId);order.setAmount(new BigDecimal("99.99"));order.setStatus(1);  // 1-待支付order.setCreateTime(LocalDateTime.now());order.setUpdateTime(LocalDateTime.now());// 插入订单,ShardingSphere会根据userId和orderId自动路由到相应的分库分表baseMapper.insert(order);return order.getOrderId();}/*** 批量创建订单*/@Transactionalpublic void batchCreateOrders(Long userId, int count) {List<Order> orders = new ArrayList<>(count);for (int i = 0; i < count; i++) {Order order = new Order();order.setUserId(userId);order.setAmount(new BigDecimal((i + 1) * 10));order.setStatus(1);order.setCreateTime(LocalDateTime.now());order.setUpdateTime(LocalDateTime.now());orders.add(order);}// 批量插入,ShardingSphere会自动分发到相应的分库分表baseMapper.batchInsert(orders);}/*** 根据用户ID查询订单*/public List<Order> getOrdersByUserId(Long userId) {// 查询会被路由到该userId对应的分库return baseMapper.selectByUserId(userId);}/*** 根据订单ID查询订单*/public Order getOrderByOrderId(Long orderId) {// 查询会被路由到该orderId对应的分库分表return baseMapper.selectByOrderId(orderId);}
}

  

package com.example.shardingspheredemo;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;/*** 应用启动类*/
@SpringBootApplication
@MapperScan("com.example.shardingspheredemo.mapper")  // 扫描Mapper接口
@EnableTransactionManagement  // 启用事务管理
public class ShardingsphereDemoApplication {public static void main(String[] args) {SpringApplication.run(ShardingsphereDemoApplication.class, args);}
}

  

spring:profiles:active: sharding  # 激活分片配置# ShardingSphere 配置shardingsphere:# 数据源配置datasource:# 数据源名称列表,多个用逗号分隔names: master0,master1,slave0,slave1# 主库0配置master0:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/order_db_0?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: roothikari:maximum-pool-size: 10minimum-idle: 5idle-timeout: 300000connection-timeout: 20000# 主库1配置master1:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/order_db_1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: roothikari:maximum-pool-size: 10minimum-idle: 5# 从库0配置(主库0的从库)slave0:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3307/order_db_0?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: root# 从库1配置(主库1的从库)slave1:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3307/order_db_1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: root# 规则配置rules:# 读写分离规则readwrite-splitting:data-sources:# 主从数据源组合名称order-db-group-0:type: Staticprops:write-data-source-name: master0  # 写数据源read-data-source-names: slave0   # 读数据源,多个用逗号分隔load-balancer-name: round_robin  # 负载均衡策略名称order-db-group-1:type: Staticprops:write-data-source-name: master1read-data-source-names: slave1load-balancer-name: round_robin# 负载均衡策略配置load-balancers:round_robin:type: ROUND_ROBIN  # 轮询策略weight:type: WEIGHT       # 权重策略(示例)props:slave0: 1slave1: 2# 分片规则配置sharding:# 表分片规则tables:# 订单表分片配置t_order:# 实际数据节点:数据库.表actual-data-nodes: order-db-group-${0..1}.t_order_${0..3}# 数据库分片策略database-strategy:standard:sharding-column: user_id  # 分片列sharding-algorithm-name: order_db_inline  # 分片算法名称# 表分片策略table-strategy:standard:sharding-column: order_id  # 分片列sharding-algorithm-name: order_table_inline  # 分片算法名称# 主键生成策略key-generate-strategy:column: order_id  # 主键列key-generator-name: snowflake  # 主键生成器名称# 订单item表分片配置t_order_item:actual-data-nodes: order-db-group-${0..1}.t_order_item_${0..3}database-strategy:standard:sharding-column: user_idsharding-algorithm-name: order_db_inlinetable-strategy:standard:sharding-column: order_idsharding-algorithm-name: order_table_inlinekey-generate-strategy:column: order_item_idkey-generator-name: snowflake# 分片算法配置sharding-algorithms:# 数据库分片算法order_db_inline:type: INLINE  # 行表达式分片算法props:algorithm-expression: order-db-group-${user_id % 2}  # 分片表达式,分2个库# 表分片算法order_table_inline:type: INLINEprops:algorithm-expression: t_order_${order_id % 4}  # 分片表达式,每个库分4个表# 主键生成器配置key-generators:snowflake:type: SNOWFLAKE  # 雪花算法props:worker-id: 1  # 工作节点ID,集群部署时需唯一max-tolerate-time-difference-milliseconds: 300000  # 最大容忍时间差# 属性配置props:# 展示SQL,开发环境开启,生产环境关闭sql-show: true# 执行引擎类型executor-size: 10# 检查表元数据一致性check-table-metadata-enabled: false# 数据库类型database-type: MySQL# MyBatis-Plus 配置
mybatis-plus:mapper-locations: classpath*:mapper/**/*.xmltype-aliases-package: com.example.shardingspheredemo.entityconfiguration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 日志输出# 日志配置
logging:level:org.apache.shardingsphere: INFOcom.example.shardingspheredemo: DEBUGcom.zaxxer.hikari: WARNroot: INFO

  

<?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.example</groupId><artifactId>shardingsphere-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>shardingsphere-demo</name><description>Demo project for Spring Boot + ShardingSphere</description><properties><java.version>11</java.version><shardingsphere.version>5.3.2</shardingsphere.version></properties><dependencies><!-- Spring Boot 核心依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- ShardingSphere 核心依赖 --><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId><version>${shardingsphere.version}</version></dependency><!-- 数据库驱动 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><!-- ORM 框架 - MyBatis-Plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version></dependency><!-- 连接池 --><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId></dependency><!-- 分布式事务 (可选) --><dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>1.6.1</version></dependency><!-- 配置中心 (可选,用于动态配置) --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId><version>2021.0.5.0</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

  

-------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------

http://www.hskmm.com/?act=detail&tid=20858

相关文章:

  • echarts4升级为echarts5的常见问题
  • ISO 周计算 记录
  • 从 “被动耗能” 到 “主动优化”:MyEMS 开启商业建筑能源管理 “新范式”
  • 【故障排查】视频汇聚EasyCVR接入设备通道数为0?通道编码长度不规范导致
  • 来信小程序管理系统:匿名信息传递与社交互动平台
  • PCIe加速卡设计资料:416-基于Kintex Ultrasacle的万兆网络光纤 PCIe加速卡
  • 多生产者,多消费者
  • GEO优化实战指南:一周内让豆包、Deepseek、Kimi等推荐了我的插件
  • 房产楼盘小程序管理系统:助力房产营销数字化升级的优质解决方案
  • 高速信号处理设计方案:413-基于双XCVU9P+C6678的100G光纤加速卡
  • Teamcenter:结构管理器查询(又称:BOM结构查询)
  • 2025年最好用的同步云盘是哪个?一个老用户的真实体验分享
  • 使用 ShedLock 实现多实例定时任务单执行的常见错误及解决办法
  • 1_二分查找
  • AI元人文:悟空博弈专用芯片
  • 【ACM出版】第五届管理科学和软件工程国际学术会议(ICMSSE 2025)
  • PiXYZ Studio 2021下载地址与安装教程
  • coremail日常操作
  • Win 10 LSTC 使用 Podman - tfel
  • 一生一芯学习:程序,运行时环境与AM(一)
  • 如何用Java25编译Java17的项目
  • [MCP] MCP Resources
  • 【ACM出版】2025年第二届人工智能与未来教育国际学术会议(AIFE 2025)
  • HL工作日志
  • Halcon基础——图像增强
  • HTML 开发工具有哪些?常用 HTML 开发工具推荐、学习路线与实战经验分享
  • PS 商业级人像修图插件:Infinite Retouch V1.0.3 全面指南
  • NVIDIA 开源 Audio2Face:音频生成逼真面部动画;Gemini Live API 支持思考能力 丨日报
  • 深入解析:4、urbane-commerce 认证请求 DTO 设计规范
  • mp4/图片转gif