Spring Boot项目实现水平分库分表及一对多关系适配问题
Spring Boot + Spring Data JPA 实现水平分库分表方案
一、核心选型:用Sharding-JDBC做分库分表
Spring Boot默认仅支持单数据源,但可以通过Sharding-JDBC(ShardingSphere生态成员)实现JDBC层的分库分表。它对Spring Data JPA友好,无需大幅修改现有业务代码,属于轻量级、侵入性低的解决方案。
二、集成步骤
1. 引入依赖
在pom.xml中添加ShardingSphere的Spring Boot starter及MySQL驱动依赖:
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> <version>5.4.1</version> <!-- 建议使用最新稳定版 --> </dependency> <dependency> <groupId>com.mysql.cj</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
2. 配置分库分表规则
以用户订单场景为例(按user_id分库,order_id分表),在application.yml中配置数据源、分片策略:
spring: shardingsphere: datasource: names: ds0,ds1 # 定义两个分库实例 ds0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/db0?useSSL=false&serverTimezone=UTC username: root password: root ds1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/db1?useSSL=false&serverTimezone=UTC username: root password: root rules: sharding: tables: t_order: # 逻辑表名,对应多个物理表 actual-data-nodes: ds$->{0..1}.t_order_$->{0..1} # 物理表集合:ds0.t_order_0/1、ds1.t_order_0/1 database-strategy: standard: sharding-column: user_id sharding-algorithm-name: user-inline # 分库算法 table-strategy: standard: sharding-column: order_id sharding-algorithm-name: order-inline # 分表算法 sharding-algorithms: user-inline: type: INLINE props: algorithm-expression: ds$->{user_id % 2} # 按user_id取模分库 order-inline: type: INLINE props: algorithm-expression: t_order_$->{order_id % 2} # 按order_id取模分表 props: sql-show: true # 打印路由后的SQL,方便调试
3. 调整JPA配置
- 禁用JPA自动建表(物理表需提前创建,或开启ShardingSphere的自动建表功能):
spring: jpa: hibernate: ddl-auto: none
- 实体类仅需指定逻辑表名,无需关联具体物理表:
@Entity @Table(name = "t_order") public class Order { @Id private Long orderId; private Long userId; // 其他字段、getter/setter }
4. 验证逻辑
直接使用Spring Data JPA的Repository操作数据,Sharding-JDBC会自动完成路由。比如插入userId=1的订单,会被路由到ds1;orderId=3的订单会被路由到t_order_1。
三、一对多关联场景的分库分表处理
假设有t_order(订单)和t_order_item(订单明细)的一对多关系,核心原则是关联表使用相同的分片键,保证数据落在同一个分片,避免跨库跨表关联的性能损耗。
1. 分片策略统一
- 让
t_order_item复用t_order的分片规则:以user_id分库,order_id分表,确保同一订单的主表和明细数据落在同一个库和表中。 - 配置示例:
spring: shardingsphere: rules: sharding: tables: t_order_item: actual-data-nodes: ds$->{0..1}.t_order_item_$->{0..1} database-strategy: standard: sharding-column: user_id sharding-algorithm-name: user-inline table-strategy: standard: sharding-column: order_id sharding-algorithm-name: order-inline
2. JPA关联查询适配
在实体类中正常使用@OneToMany/@ManyToOne关联,只要分片键一致,Sharding-JDBC会自动路由到对应分片完成关联:
@Entity @Table(name = "t_order") public class Order { @Id private Long orderId; private Long userId; @OneToMany(mappedBy = "order", fetch = FetchType.LAZY) private List<OrderItem> items; // ... } @Entity @Table(name = "t_order_item") public class OrderItem { @Id private Long itemId; private Long orderId; private Long userId; // 冗余user_id用于分库路由 @ManyToOne @JoinColumn(name = "order_id") private Order order; // ... }
3. 关键注意事项
- 禁止跨分片关联:如果两张表分片键不一致,会触发全库全表扫描,性能极差,必须保证关联数据在同一个分片。
- 复杂查询拆分:若需跨分片查询关联数据,建议拆分逻辑:先查询主表获取分片键集合,再根据分片键批量查询从表,避免直接执行跨分片关联JPQL。
- 跨库事务处理:需开启ShardingSphere的XA事务或柔性事务,配置示例:
spring: shardingsphere: rules: transaction: default-type: XA provider-type: Atomikos
内容的提问来源于stack exchange,提问作者dead programmer
相关产品推荐
相关产品推荐

