一 什么是 shardingsphere?
1.1 背景:为什么需要分库分表?
随着系统数据量和用户量不断增长,传统单体数据库容易遇到瓶颈:
写入/查询压力大:单表千万级数据,索引效率下降。
存储超限:单机磁盘空间和 iops 不堪重负。
水平扩展困难:业务难以横向拓展。
为了解决这些问题,开发者往往采用 分库分表 技术,将一张大表分成多个小表,分布在不同数据库中,实现水平扩展和负载均衡。
1.2 什么是 apache shardingsphere?
apache shardingsphere 是一款开源的 分布式数据库中间件框架,可以帮助开发者轻松实现:
- 分库分表
- 读写分离
- 分布式事务
- 数据脱敏
- 可观测性 & 扩展治理能力
shardingsphere 核心组件包括:
| 组件 | 说明 |
|---|---|
| shardingsphere-jdbc | jdbc 封装层,嵌入应用中,适用于微服务架构 |
| shardingsphere-proxy | 独立部署的数据库代理,支持多语言访问 |
| shardingsphere-sidecar(规划中) | 面向云原生场景,service mesh 结构 |
1.3 shardingsphere-jdbc 的核心功能
| 功能 | 简要说明 |
|---|---|
| 分库分表 | 按字段配置路由策略,自动将 sql 分发到对应的数据库/表 |
| 读写分离 | 自动区分读写请求,路由到主/从数据库 |
| 灵活分片策略 | 支持取模、范围、hint、自定义算法等多种策略 |
| 事务支持 | 支持本地事务和分布式事务(seata/xa) |
| 透明化使用 | 对开发者来说使用方式与普通 jdbc 几乎一致,只需配置逻辑表名 |
二、实践部分:java + h2 实现分库分表
示例:使用 java 原生程序 + shardingsphere-jdbc + h2 内存数据库,模拟一个电商订单系统按 user_id 分库,order_id 分表。
2.1 项目结构
- 使用 h2 数据库模拟两个库
ds0,ds1 - 每个库中创建两个分表
t_order_0,t_order_1 - 逻辑表名:
t_order
2.2 maven 依赖配置
<dependencies>
<dependency>
<groupid>org.apache.shardingsphere</groupid>
<artifactid>shardingsphere-jdbc-core</artifactid>
<version>5.4.1</version>
</dependency>
<dependency>
<groupid>com.h2database</groupid>
<artifactid>h2</artifactid>
<version>2.2.220</version>
</dependency>
<dependency>
<groupid>com.zaxxer</groupid>
<artifactid>hikaricp</artifactid>
<version>5.0.1</version>
</dependency>
</dependencies>2.3 核心代码结构
1. 创建真实表(物理分表)
public static void createtables() throws sqlexception {
for (int i = 0; i < 2; i++) {
string db = "ds" + i;
try (connection conn = drivermanager.getconnection("jdbc:h2:mem:" + db + ";db_close_delay=-1;mode=mysql", "sa", "")) {
statement stmt = conn.createstatement();
for (int j = 0; j < 2; j++) {
stmt.execute(string.format("""
create table if not exists t_order_%d (
order_id bigint primary key,
user_id int,
status varchar(50)
)
""", j));
}
}
}
}2. 配置分库分表数据源
public static datasource createdatasource() throws sqlexception {
map<string, datasource> datasourcemap = new hashmap<>();
for (int i = 0; i < 2; i++) {
hikaridatasource ds = new hikaridatasource();
ds.setjdbcurl("jdbc:h2:mem:ds" + i + ";db_close_delay=-1;mode=mysql");
ds.setusername("sa");
ds.setpassword("");
datasourcemap.put("ds" + i, ds);
}
shardingtableruleconfiguration ordertablerule = new shardingtableruleconfiguration(
"t_order", "ds${0..1}.t_order_${0..1}");
ordertablerule.setdatabaseshardingstrategy(
new standardshardingstrategyconfiguration("user_id", "dbsharding"));
ordertablerule.settableshardingstrategy(
new standardshardingstrategyconfiguration("order_id", "tablesharding"));
shardingruleconfiguration config = new shardingruleconfiguration();
config.gettables().add(ordertablerule);
config.getshardingalgorithms().put("dbsharding",
new algorithmconfiguration("inline", props("algorithm-expression", "ds${user_id % 2}")));
config.getshardingalgorithms().put("tablesharding",
new algorithmconfiguration("inline", props("algorithm-expression", "t_order_${order_id % 2}")));
return shardingspheredatasourcefactory.createdatasource(datasourcemap, list.of(config), new properties());
}3. 插入与查询数据
public static void insertorder(datasource ds, long orderid, int userid, string status) throws sqlexception {
try (connection conn = ds.getconnection()) {
preparedstatement ps = conn.preparestatement("insert into t_order (order_id, user_id, status) values (?, ?, ?)");
ps.setlong(1, orderid);
ps.setint(2, userid);
ps.setstring(3, status);
ps.executeupdate();
}
}
public static void queryorders(datasource ds) throws sqlexception {
try (connection conn = ds.getconnection()) {
resultset rs = conn.createstatement().executequery("select * from t_order");
while (rs.next()) {
system.out.printf("order_id=%d, user_id=%d, status=%s%n",
rs.getlong("order_id"),
rs.getint("user_id"),
rs.getstring("status"));
}
}
}2.4 程序入口
public static void main(string[] args) throws exception {
createtables(); // 创建实际分表
datasource shardingdatasource = createdatasource();
insertorder(shardingdatasource, 1001, 1, "init");
insertorder(shardingdatasource, 1002, 2, "paid");
insertorder(shardingdatasource, 1003, 3, "shipped");
queryorders(shardingdatasource);
}输出示例
order_id=1001, user_id=1, status=init
order_id=1002, user_id=2, status=paid
order_id=1003, user_id=3, status=shipped
shardingsphere 已自动根据你配置的策略将数据路由到对应的库和表!
总结
apache shardingsphere 提供了强大、灵活的分库分表能力,通过合理配置可以极大提升系统的性能与扩展性:
- 分片策略灵活,支持多种规则或自定义算法
- 配置简单,无需改动业务 sql
- 兼容性强,支持 jdbc、spring boot、yaml 等多种使用方式
无论你是中小项目的快速原型,还是大规模高并发系统,shardingsphere 都是一个值得一试的解决方案。
完整代码
package org.example;
import com.zaxxer.hikari.hikaridatasource;
import org.apache.shardingsphere.driver.api.shardingspheredatasourcefactory;
import org.apache.shardingsphere.infra.config.algorithm.algorithmconfiguration;
import org.apache.shardingsphere.sharding.api.config.shardingruleconfiguration;
import org.apache.shardingsphere.sharding.api.config.rule.shardingtableruleconfiguration;
import org.apache.shardingsphere.sharding.api.config.strategy.sharding.standardshardingstrategyconfiguration;
import javax.sql.datasource;
import java.sql.*;
import java.util.*;
public class shardingh2example {
public static void main(string[] args) throws exception {
createtables(); // 注意:用 drivermanager 直连底层 db 建表
datasource shardingdatasource = createdatasource();
// 插入测试数据
insertorder(shardingdatasource, 1001, 1, "init");
insertorder(shardingdatasource, 1002, 2, "paid");
insertorder(shardingdatasource, 1003, 3, "shipped");
// 查询测试数据
queryorders(shardingdatasource);
}
public static datasource createdatasource() throws exception {
map<string, datasource> datasourcemap = new hashmap<>();
// 模拟两个库:ds0 和 ds1(分别用两个内存 h2 实例模拟)
for (int i = 0; i < 2; i++) {
hikaridatasource ds = new hikaridatasource();
ds.setjdbcurl("jdbc:h2:mem:ds" + i + ";db_close_delay=-1;mode=mysql");
ds.setusername("sa");
ds.setpassword("");
datasourcemap.put("ds" + i, ds);
}
// 分表规则配置
shardingtableruleconfiguration ordertablerule = new shardingtableruleconfiguration(
"t_order", "ds${0..1}.t_order_${0..1}");
// 分库策略(user_id)
ordertablerule.setdatabaseshardingstrategy(new standardshardingstrategyconfiguration(
"user_id", "dbsharding"));
// 分表策略(order_id)
ordertablerule.settableshardingstrategy(new standardshardingstrategyconfiguration(
"order_id", "tablesharding"));
shardingruleconfiguration shardingruleconfig = new shardingruleconfiguration();
shardingruleconfig.gettables().add(ordertablerule);
properties dbprops = new properties();
dbprops.setproperty("algorithm-expression", "ds${user_id % 2}");
shardingruleconfig.getshardingalgorithms().put("dbsharding",
new algorithmconfiguration("inline", dbprops));
properties tableprops = new properties();
tableprops.setproperty("algorithm-expression", "t_order_${order_id % 2}");
shardingruleconfig.getshardingalgorithms().put("tablesharding",
new algorithmconfiguration("inline", tableprops));
return shardingspheredatasourcefactory.createdatasource(datasourcemap, list.of(shardingruleconfig), new properties());
}
public static void createtables() throws sqlexception {
for (int i = 0; i < 2; i++) {
string dbname = "ds" + i;
try (connection conn = drivermanager.getconnection("jdbc:h2:mem:" + dbname + ";db_close_delay=-1;mode=mysql", "sa", "")) {
statement stmt = conn.createstatement();
for (int j = 0; j < 2; j++) {
string sql = string.format("""
create table if not exists t_order_%d (
order_id bigint primary key,
user_id int,
status varchar(50)
)
""", j);
stmt.execute(sql);
}
}
}
}
// 辅助方法用于手动连接底层 h2 数据源
private static hikaridatasource geth2datasource(string name) {
hikaridatasource ds = new hikaridatasource();
ds.setjdbcurl("jdbc:h2:mem:" + name + ";db_close_delay=-1;mode=mysql");
ds.setusername("sa");
ds.setpassword("");
return ds;
}
public static void insertorder(datasource ds, long orderid, int userid, string status) throws sqlexception {
try (connection conn = ds.getconnection()) {
preparedstatement ps = conn.preparestatement("insert into t_order (order_id, user_id, status) values (?, ?, ?)");
ps.setlong(1, orderid);
ps.setint(2, userid);
ps.setstring(3, status);
ps.executeupdate();
}
}
public static void queryorders(datasource ds) throws sqlexception {
try (connection conn = ds.getconnection()) {
resultset rs = conn.createstatement().executequery("select * from t_order");
system.out.println("query results:");
while (rs.next()) {
system.out.printf("order_id: %d, user_id: %d, status: %s%n",
rs.getlong("order_id"),
rs.getint("user_id"),
rs.getstring("status"));
}
}
}
}到此这篇关于apache shardingsphere 初识使用的文章就介绍到这了,更多相关apache shardingsphere使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论