Sharding-JDBC 分库分表-基于Yaml配置
ShardingSphere
https://shardingsphere.apache.org/document/current/cn/overview/
官方文档将 ShardingSphere 定义为 分布式的数据库生态系统
它包含 Sharding-JDBC 和 Sharding-Proxy 两部分:
Sharding-JDBC: 在 Java 的 JDBC 层上提供额外的服务
ShardingSphere-Proxy: 透明的数据库代理
它提供的功能还是很强大,本次我们只聚焦于 Sharding-JDBC 的数据分片.
像下图所示,在 Spring-Boot 应用中,Sharding-JDBC 的角色其实是在 datasource 层,
它根据用户配置的分片规则,在接收到上层的查询请求后,对具体的数据库和表进行定位,查询返回结果给 ORM 层.
所以,配置 Sharding-JDBC 的步骤也显而易见:
- 配置 Sharding-JDBC 为 Spring 的 datasource
- 通过 datasource 创建一个SQL 会话工厂: SQLSessionFactory
- 将 SQLSessionFactory 配置给 ORM (我们使用 Mybatis)
快速接入
配置 Sharding-JDBC
Sharding-JDBC 的配置主要包括:
数据源配置:
- dataSources 数据源配置
规则配置:
- defaultDatabaseStrategy:数据库分片配置
- tables 表分片配置
- shardingAlgorithms 分片算法配置
- keyGenerators 主键生成算法配置
- auditors 分片审计算法配置(暂时未用到)
我测试的项目里共有:
4个数据库实例 | demo_ds_0 ~ demo_ds_3 |
每个数据库有 6 张表 | t_order_0 ~ t_order_1 |
每个表有两个字段 | user_id, order_id |
库的分片算法 | ds_${user_id % 4} |
表的分片算法 | ds_${user_id % 6} |
主键生成算法 | sharding-jdbc 自带的雪花算法 SNOWFLAKE |
数据库分片的目标是:
将相同用户(user_id)的数据放在同一个库里,每个库里的订单表均匀分布在每张表里
下面是我测试所用的 yaml 配置:
dataSources:
ds_xd_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.jdbc.driver
jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: 123456
ds_1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.jdbc.driver
jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: 123456
ds_2:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.jdbc.driver
jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: 123456
ds_3:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.jdbc.driver
jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_2?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: 123456
rules:
- !SHARDING
tables:
t_order:
actualDataNodes: ds_${0..3}.t_order_${0..5}
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: t_order_inline
keyGenerateStrategy:
column: id
keyGeneratorName: snowflake
defaultDatabaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: database_inline
shardingAlgorithms:
database_inline:
type: INLINE
props:
algorithm-expression: ds_${user_id % 4}
t_order_inline:
type: INLINE
props:
algorithm-expression: t_order_${order_id % 6}
keyGenerators:
snowflake:
type: SNOWFLAKE
配置 Spring datasource
datasource.url 指向我们上面创建的 yaml 文件
spring.datasource.driver-class-name=org.apache.shardingsphere.driver.ShardingSphereDriver
spring.datasource.url=jdbc:shardingsphere:classpath:sharding.yaml
配置 ORM (Mybatis)
首先配置 SqlSessionFactory
@Configuration
public class DataSourceConfiguration {
@Resource
private DataSource dataSource;
@Bean(name = "mqSqlSessionFactory")
public SqlSessionFactory mqSqlSessionFactory() {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
//实体扫描
bean.setTypeAliasesPackage("com.kong.demo.dao.model");
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
//mapper映射文件加载
bean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
bean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
return bean.getObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
然后配置 MapperScannerConfigurer
@Configuration
public class MyBatisMapperScannerConfiguration {
@Bean("ubudMapperScannerConfigurer")
public MapperScannerConfigurer ubudMapperScannerConfigurer() {
MapperScannerConfigurer mapper = new MapperScannerConfigurer();
mapper.setSqlSessionFactoryBeanName("mqSqlSessionFactory");
mapper.setBasePackage("com.kong.demo.dao");
return mapper;
}
}
mapper 文件如下,为了测试,我加入了一个 insert 方法:
<?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">
<mapper namespace="so.dian.cs.mg.dao.OrderDAO">
<resultMap id="BaseResultMap" type="so.dian.cs.mg.dao.model.Order">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="order_id" property="orderId" />
<result column="user_id" property="userId" />
</resultMap>
<insert id="insert" parameterType="so.dian.cs.mg.dao.OrderDAO">
insert into t_order (order_id, user_id) values (#{orderId}, #{userId})
</insert>
</mapper>
完成上面的配置后,写一个测试接口,用不同的userId, orderId, 试着向数据库里插入数据测试,发现已经
按照预期插入了对应的库和对应的表。
总结
本期简单记录了下使用 yaml配置文件的形式,往 spring-boot 应用里接入 sharding-jdbc的过程。在实际的项目
开发中,更多还是使用 Java 配置的形式来进行数据分片的配置,后面将会分期记录分享.
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。