我们先了解一下什么是ShardingSphere:
Apache ShardingSphere 是一款分布式的数据库生态系统,可以将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。
Apache ShardingSphere 设计哲学为 Database Plus,旨在构建异构数据库上层的标准和生态。 它关注如何充分合理地利用数据库的计算和存储能力,而并非实现一个全新的数据库。 它站在数据库的上层视角,关注它们之间的协作多于数据库自身。
ShardingSphere-JDBC 定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
- 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC;
- 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, HikariCP 等;
- 支持任意实现 JDBC 规范的数据库,目前支持 MySQL,PostgreSQL,Oracle,SQLServer 以及任何可使用 JDBC 访问的数据库。
那为什么写这篇文章呢?在决定使用shardingsphere-jdbc进行分表的时候,网上都是使用的 shardingsphere-jdbc-core-spring-boot-starter来进行集成的,但是maven仓库最新版本的shardingsphere-jdbc-core-spring-boot-starter只到5.2.1且最后发布时间是2022年。
所以才会有这篇文章的诞生。由于本人第一次写,各位大佬请担待。
集成正式开始,各位小伙伴请坐好。
本次集成采用的springboot版本为3.3.2。
pom文件需要引入 shardingsphere-jdbc 及orm框架 orm框架自己选择即可 jpa 与 mybatis都可以:
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc</artifactId>
<version>5.5.0</version>
<!--找不到这个包排除掉 不影响使用-->
<exclusions>
<exclusion>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-test-util</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
接下来我们配置sharding-db.yml
mode:
type: Standalone
repository:
type: JDBC
dataSources: # 数据源配置 YamlJDBCConfiguration
ds_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.jdbc.Driver
jdbcUrl: jdbc:mysql://localhost:3306/sharding_db?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: root
rules: # YamlShardingRuleConfiguration
- !SHARDING
tables: # 数据分片规则配置
t_order:
actualDataNodes: ds_0.t_order_${0..3}
tableStrategy: # 分表策略,同分库策略 databaseStrategy 三种模式 standard 用于单分片键的标准分片场景, complex 用于多分片键的复合分片场景, hint 分片策略 onoe 不分片
complex:
shardingColumns: order_seq,buyer_id # 分片列名称 订单号,买家id
shardingAlgorithmName: order-sharding # 分片算法名称
keyGenerateStrategy: # 分布式序列策略 不配置也可以 下面配置了默认的
column: id # 自增列名称,缺省表示不使用自增主键生成器
keyGeneratorName: snowflake # 分布式序列算法名称
# 分片算法配置
shardingAlgorithms:
order-sharding: # 分片算法名称 需要和上面的对应上
type: CLASS_BASED # 分片算法类型 org.apache.shardingsphere.sharding.spi.ShardingAlgorithm ClassBasedShardingAlgorithm
props:
algorithmClassName: com.example.shardingjdbcdemo.config.OrderComplexKeysShardingAlgorithm
strategy: complex # CLASS_BASED 这个必须配置 ClassBasedShardingAlgorithm 会判断类型
# 分布式序列算法配置
keyGenerators:
snowflake: # 分布式序列算法名称 和上面的keyGeneratorName对应
type: SNOWFLAKE # 分布式序列算法类型
defaultKeyGenerateStrategy:
column: id
keyGeneratorName: snowflake
defaultDatabaseStrategy:
none:
# 分片审计算法配置
auditors:
sharding_key_required_auditor:
type: DML_SHARDING_CONDITIONS
# 不需要分表的配置
- !SINGLE
tables: # YamlSingleRuleConfiguration
- "ds_0.*"
defaultDataSource: ds_0 # 只用于create table 生效
props:
sql-show: true
application.yml配置
spring:
application:
name: sharding-jdbc-demo
datasource:
driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
url: jdbc:shardingsphere:classpath:sharding-db.yml
data:
jdbc:
dialect: mysql
main:
allow-bean-definition-overriding: true
mybatis:
configuration:
map-underscore-to-camel-case: true
mapper-locations: classpath:mapper/*.xml
自定义分片算法:
package com.example.shardingjdbcdemo.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingValue;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
@Component
@Slf4j
public class OrderComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<String> {
/**
* 分片
* @param collection 表名称 t_order_0 t_order_1 t_order_2 t_order_3
* @param complexKeysShardingValue 原表名称t_order 分片列名称 order_seq buyer_id
* @return
*/
@Override
public Collection<String> doSharding(Collection<String> collection, ComplexKeysShardingValue<String> complexKeysShardingValue) {
log.info("collection:{}",collection);
//返回使用的表名称
Collection<String> result = new HashSet<>();
String logicTableName = complexKeysShardingValue.getLogicTableName();
// map存储的 order_seq buyer_id 的值 分片的字段
Map<String, Collection<String>> columnNameAndShardingValuesMap = complexKeysShardingValue.getColumnNameAndShardingValuesMap();
//存在买家id 按照买家分片
Collection<String> columnValues = columnNameAndShardingValuesMap.get("buyer_id");
if (!CollectionUtils.isEmpty(columnValues)) {
for (String columnValue : columnValues) {
String tableName = getTableName(logicTableName, columnValue);
result.add(tableName);
}
return result;
}
// 不存在的时候如何处理 其实就是订单号
columnNameAndShardingValuesMap.forEach((k,otherColumnValues)->{
for (String otherColumnValue : otherColumnValues) {
String tableName = getTableName(logicTableName, otherColumnValue);
result.add(tableName);
}
});
return result;
}
/**
* 获取表名称 分片数量也可以动态设置,这里写死了分4张表
* @param logicTableName
* @param columnValue
* @return
*/
private String getTableName(String logicTableName,String columnValue){
return logicTableName + "_" + (Math.abs(columnValue.hashCode()) % 4);
}
}
本人对t_order、t_order_item 同时进行了分表操作 t_order采用jpa t_order_item采用mybatis
jpa 对应的配置如下: 实体类:
package com.example.shardingjdbcdemo.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import java.math.BigDecimal;
@Table(name = "t_order")
@Setter
@Getter
@Entity
public class Order {
/**
* 需要标识id 作为主键 需要使用 spring的注解id 不能使用jdk的
*/
@Id
private Long id;
/**
* 商品名称
*/
private String goodsName;
/**
* 买家id
*/
private String buyerId;
/**
* 价格
*/
private BigDecimal price;
/**
* 订单号 订单号生成带有 表标识
*/
private String orderSeq;
}
jpa repository
@Repository
public interface OrderRepository extends CrudRepository<Order,Long> {
}
如果使用mybatis 参考下面配置:
package com.example.shardingjdbcdemo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName(value = "t_order_item")
public class OrderItem {
private Long id;
private String orderSeq;
private String goodsName;
}
@Mapper
public interface OrderItemMapper extends BaseMapper<OrderItem> {
}