1.Sharding-Jdbc介绍
Sharding-Jdbc在3.0后改名为ShardingSphere它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成。他们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如Java同构、异构语言、容器、云原生等各种多样化的应用场景。
Sharding-Sphere定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。它通过关注不变,进而抓住事物本质。关系型数据库当今依然占有巨大市场,是各个公司核心业务的基石,未来也难于撼动,我们目前阶段更加关注在原有基础上的增量,而非颠覆。
应用场景:
数据库读写分离
数据库分表分库
2.Sharding-Jdbc与MyCat区别
MyCat是一个基于第三方应用中间件数据库代理框架,客户端所有的jdbc请求都必须要先交给MyCat,再有MyCat转发到具体的真实服务器中。
Sharding-Jdbc是一个Jar形式,在本地应用层重写Jdbc原生的方法,实现数据库分片形式。
MyCat属于服务器端数据库中间件,而Sharding-Jdbc是一个本地数据库中间件框架。
从设计理念上看确实有一定的相似性。主要流程都是SQL 解析 -> SQL 路由 -> SQL 改写 -> SQL 执行 -> 结果归并。但架构设计上是不同的。Mycat 是基于 Proxy,它复写了 MySQL 协议,将 Mycat Server 伪装成一个 MySQL 数据库,而 Sharding-JDBC 是基于 JDBC 的扩展,是以 jar 包的形式提供轻量级服务的。
3.Sharding-Jdbc日志分析与原理图
1.Sharding-JDBC中的路由结果是通过分片字段和分片方法来确定的,如果查询条件中有 id 字段的情况还好,查询将会落到某个具体的分片
2.如果查询没有分片的字段,会向所有的db或者是表都会查询一遍,让后封装结果级给客户端。
Sharding-Jdbc和MyCat查询原理大致相同
4.Sharding-Jdbc日志分析与原理图
一种为原生配置方式,自己需要实现接口。
1.分库算法类需要实现SingleKeyDatabaseShardingAlgorithm接口
2.分表算法类需要实现SingleKeyTableShardingAlgorithm接口
第二种通过配置文件形式配置
4.1单库分表
DataSourceConfig
// 数据源相关配置信息
@Configuration
public class DataSourceConfig {
@Value("${spring.jdbc.db0.className}")
private String className;
@Value("${spring.jdbc.db0.url}")
private String url;
@Value("${spring.jdbc.db0.username}")
private String username;
@Value("${spring.jdbc.db0.password}")
private String password;
@Bean
public IdGenerator getIdGenerator() {
return new CommonSelfIdGenerator();
}
@Bean
public DataSource getDataSource() {
return buildDataSource();
}
private DataSource buildDataSource() {
// 1.设置分库映射
Map<String, DataSource> dataSourceMap = new HashMap<>(2);
dataSourceMap.put("userdb_1", createDataSource("userdb_1"));
// dataSourceMap.put("ds_1", createDataSource("ds_1"));
// 设置默认db为ds_0,也就是为那些没有配置分库分表策略的指定的默认库
// 如果只有一个库,也就是不需要分库的话,map里只放一个映射就行了,只有一个库时不需要指定默认库,
// 但2个及以上时必须指定默认库,否则那些没有配置策略的表将无法操作数据
DataSourceRule rule = new DataSourceRule(dataSourceMap, "userdb_1");
// 2.设置分表映射,将t_order_0和t_order_1两个实际的表映射到t_order逻辑表
TableRule orderTableRule = TableRule.builder("t_order").actualTables(Arrays.asList("t_order_0", "t_order_1"))
.dataSourceRule(rule).build();
// 3.具体的分库分表策略
ShardingRule shardingRule = ShardingRule.builder().dataSourceRule(rule)
.tableRules(Arrays.asList(orderTableRule))
// 根据userid分片字段
.tableShardingStrategy(new TableShardingStrategy("user_id", new TableShardingAlgorithm())).build();
// 创建数据源
DataSource dataSource = ShardingDataSourceFactory.createDataSource(shardingRule);
return dataSource;
}
private DataSource createDataSource(String dataSourceName) {
// 使用druid连接数据库
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(className);
druidDataSource.setUrl(String.format(url, dataSourceName));
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}
}
TableShardingAlgorithm
/**
* @author Administrator
*/ // 表分片算法
public class TableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Long> {
// sql 中关键字 匹配符为 =的时候,表的路由函数
public String doEqualSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {
for (String tableName : availableTargetNames) {
if (tableName.endsWith(shardingValue.getValue() % 2 + "")) {
return tableName;
}
}
throw new IllegalArgumentException();
}
@Override
public Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {
return null;
}
@Override
public Collection<String> doBetweenSharding(Collection<String> availableTargetNames,
ShardingValue<Long> shardingValue) {
return null;
}
}
4.2分库分表
DataSourceConfig
// 数据源相关配置信息
@Configuration
public class DataSourceConfig {
@Value("${spring.jdbc.db0.className}")
private String className;
@Value("${spring.jdbc.db0.url}")
private String url;
@Value("${spring.jdbc.db0.username}")
private String username;
@Value("${spring.jdbc.db0.password}")
private String password;
@Bean
public IdGenerator getIdGenerator() {
return new CommonSelfIdGenerator();
}
@Bean
public DataSource getDataSource() {
return buildDataSource();
}
private DataSource buildDataSource() {
// 1.设置分库映射
Map<String, DataSource> dataSourceMap = new HashMap<>(2);
dataSourceMap.put("userdb_0", createDataSource("userdb_0"));
dataSourceMap.put("userdb_1", createDataSource("userdb_1"));
// 设置默认db为ds_0,也就是为那些没有配置分库分表策略的指定的默认库
// 如果只有一个库,也就是不需要分库的话,map里只放一个映射就行了,只有一个库时不需要指定默认库,
// 但2个及以上时必须指定默认库,否则那些没有配置策略的表将无法操作数据
DataSourceRule rule = new DataSourceRule(dataSourceMap, "userdb_1");
// 2.设置分表映射,将t_order_0和t_order_1两个实际的表映射到t_order逻辑表
TableRule orderTableRule = TableRule.builder("t_order").dataSourceRule(rule).build();
// 3.具体的分库分表策略
ShardingRule shardingRule = ShardingRule.builder().dataSourceRule(rule)
.tableRules(Arrays.asList(orderTableRule))
.databaseShardingStrategy(new DatabaseShardingStrategy("user_id", new DatabaseShardingAlgorithm()))
.build();
// 创建数据源
DataSource dataSource = ShardingDataSourceFactory.createDataSource(shardingRule);
return dataSource;
}
private DataSource createDataSource(String dataSourceName) {
// 使用druid连接数据库
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(className);
druidDataSource.setUrl(String.format(url, dataSourceName));
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}
}
DatabaseShardingAlgorithm
public class DatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<Long> {
@Override
public String doEqualSharding(Collection<String> databases, ShardingValue<Long> shardingValue) {
for (String tableName : databases) {
System.out.println("tableName:" + tableName + ",----" + shardingValue.getValue());
if (tableName.endsWith(shardingValue.getValue() % 2 + "")) {
return tableName;
}
}
throw new IllegalArgumentException();
}
@Override
public Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {
return null;
}
@Override
public Collection<String> doBetweenSharding(Collection<String> availableTargetNames,
ShardingValue<Long> shardingValue) {
return null;
}
}
4.3配置文件(单库分表)
spring:
jpa:
show-sql: true
hibernate:
ddl-auto: none
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
sharding:
jdbc:
####ds1
datasource:
names: userdb3
userdb3:
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.223.141:3306/userdb3
username: root
config:
sharding:
tables:
t_order:
table-strategy:
inline:
#### 根据userid 进行分片
sharding-column: user_id
algorithm-expression: userdb3.t_order_$->{user_id % 2}
actual-data-nodes: userdb3.t_order_$->{0..1}
props:
sql:
### 开启分片日志
show: true
mybatis:
configuration:
map-underscore-to-camel-case: true
mapperLocations: classpath:mybatis/*.xml
type-aliases-package: com.mayikt.entity