SpringBoot整合ShardingSphere实现分表分库读写分离读写分
离+数据库分表
⽬录
前⾔
Apache ShardingSphere 是⼀套开源的分布式数据库解决⽅案组成的⽣态圈,旨在充分合理地在分布式的场景下利⽤关系型数据库的计算和存储能⼒。具体内容请看官⽅。本⽂主要记录⼀下Springboot整合ShardingSphere,并实现精确分⽚算法、范围分⽚算法、复合分⽚算法、读写分离、读写分离+分表的配置记录。
SpringBoot整合ShardingSphere
maven依赖
<dependencies>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>4.1.1</version>
</dependency>
<!-- mvnrepository/artifact/org.apache.shardingsphere/sharding-jdbc-core -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.14</version>
</dependency>
<dependency>
<groupId&batis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>org.apachemons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
⾏表达式分⽚策略
⾏表达式分辨策略使⽤Groovy的表达式,提供对SQL语句中的=和IN的分⽚操作并且只⽀持单分⽚(针对⼀个字段分⽚例如id)的操作。例如tb_user_$->{id%2}表⽰通过id对2取模,实现的效果是tb_user_0存放id为偶数的数据,tb_user_1存放id为奇数的数据。
配置⽂件如下
#基于⾏策略实现的分表分库
spring:
shardingsphere:
shardingsphere:
datasource:
#数据源名称,多个值⽤逗号隔开
names: ds0,ds1
ds0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: sql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test_1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimez username: root
password: root
ds1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: sql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test_2?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimez username: root
password: root
sharding:
tables:
tb_user: #逻辑表名,需要与mapper中sql语句中的表名⼀致
actual-data-nodes: ds$->{0..1}.tb_user_$->{0..1} #实际的节点名称例如 ds0.tb_user_0,ds0.tb_user_1,ds1.tb_user_0,ds1.tb_user_1
table-strategy:
inline:
sharding-column: id #分⽚字段
algorithm-expression: tb_user_$->{id % 2} #分表表达式
database-strategy:
inline:
sharding-column: id
algorithm-expression: ds$->{id % 2} #分库表达式
key-generator:
column: id #id⽣成策略,雪花算法,uuid
type: SNOWFLAKE
default-data-source-name: ds0 #不进⾏分表分库的表,操作的默认数据源
props:
sql:
show: true #显⽰sql
#注意
#没有分库,只分表的情况下,不需要配置分库策略,配置如下。结果是ds0.tb_user_0,ds0.tb_user_1
#sharding:
# tables:
# tb_user: #逻辑表名,需要与mapper中sql语句中的表名⼀致
# actual-data-nodes: ds0.tb_user_$->{0..1} #实际的节点名称例如 ds0.tb_user_0,ds0.tb_user_1
# table-strategy:
# inline:
# sharding-column: id #分⽚字段
# algorithm-expression: tb_user_$->{id % 2} #分表表达式
# key-generator:
# column: id #id⽣成策略,雪花算法,uuid
# type: SNOWFLAKE
#如果只分库,不分表,那么需要每个库中的表名称表结构是⼀样的,那么配置格式如下springboot推荐算法
#sharding:
# tables:
# tb_user: #逻辑表名,需要与mapper中sql语句中的表名⼀致
# actual-data-nodes: ds$->{0..1}.tb_user #实际的节点名称例如 ds0.tb_user,ds1.tb_user
# database-strategy:
# inline:
# sharding-column: id
# algorithm-expression: ds$->{id % 2} #分库表达式
# key-generator:
# column: id #id⽣成策略,雪花算法,uuid
# type: SNOWFLAKE
#如果按照最上⾯的配置,结果将是ds0.tb_user_0,ds1.tb_user_1两张表有数据,其他的表将不会存放数据,此时就需要标准分⽚算法来实现。
标准分⽚策略
标准分⽚策略提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分⽚操作⽀持。StandardShardingStrategy只⽀持单分⽚键,
提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分⽚算法。PreciseShardingAlgorithm是必选的,⽤于处理=和IN的
分⽚。RangeShardingAlgorithm是可选的,⽤于处理BETWEEN AND, >, <, >=, <=分⽚,如果不配置RangeShardingAlgorithm,SQL
中的BETWEEN AND将按照全库路由处理。
配置⽂件
#标准分⽚策略
spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: sql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test_1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimez username: root
password: root
ds1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: sql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test_2?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimez username: root
password: root
sharding:
tables:
tb_user: #逻辑表名
actual-data-nodes: ds$->{0..1}.tb_user_$->{0..1} #实际的数据库节点
key-generator:
column: id
type: SNOWFLAKE
database-strategy:
standard: #⾃定义数据库分⽚算法
sharding-column: age
range-algorithm-class-name: com.xiaojie.sharding.sphere.shardingalgorithm.MyDBShardingAlgorithm
precise-algorithm-class-name: com.xiaojie.sharding.sphere.shardingalgorithm.MyDBShardingAlgorithm
table-strategy:
standard: #⾃定义表分⽚算法
sharding-column: id
range-algorithm-class-name: com.xiaojie.sharding.sphere.shardingalgorithm.MyTableShardingAlgorit
hm
precise-algorithm-class-name: com.xiaojie.sharding.sphere.shardingalgorithm.MyTableShardingAlgorithm
default-data-source-name: ds0 #不使⽤分表分库策略的数据源
props:
sql:
show: true #显⽰sql
⾃定义算法类
⾃定义分⽚算法可以根据⾃⼰的需要,如按照年、季度、⽉、星期、天、或者地区等等需要⾃⼰实现规则。
数据库⾃定义分⽚算法
package com.xiaojie.sharding.sphere.shardingalgorithm;
llect.Range;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;
/**
* @Description:⾃定义数据库分⽚算法数据库的分⽚字段可以和分表分⽚字段⼀样,也可以不⼀样
* 下⾯配置分库字段按照age字段,如果年龄超过30那么放在ds0,如果没有超过放在ds1,
* 分表字段按照id字段存放。偶数存放到tb_user_0、奇数存放到tb_user_1
* @author: yan
* @date: 2022.03.12
*/
@Component
public class MyDBShardingAlgorithm implements PreciseShardingAlgorithm<Integer>, RangeShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> dbNames, PreciseShardingValue<Integer> shardingValue) {
// for (String dbName : dbNames) {
// /**
// * 取模算法,分⽚健 % 表数量数据库
// */
// Integer age = Value();
// String tableIndex = age%dbNames.size()+"";
// if (dsWith(tableIndex)) {
// return dbName;//返回数据库名称⽐如db0,db1
// }
// }
//如果⼤于30岁放在db0,⼩于等于30放在db1
if (Value() > 30) {
return (String) Array()[0];
} else {
return (String) Array()[1];
}
// throw new IllegalArgumentException();
}
@Override
public Collection<String> doSharding(Collection<String> dbNames, RangeShardingValue<Long> shardingValue) {
Collection<String> collect = new ArrayList<>();//数据库节点名称
Range valueRange = ValueRange();//查询返回
String lowerPoint = String.valueOf(valueRange.hasLowerBound() ? valueRange.lowerEndpoint() : "");//下限
String upperPoint = String.valueOf(valueRange.hasUpperBound() ? valueRange.upperEndpoint() : "");//上限
//判断上限,下限值是否存在,如果不存在赋给默认值。⽤于处理查询条件中只有 >或<⼀个条件,不是⼀个范围查询的情况 long lowerEndpoint = 0; //最⼩值
long lupperEndpoint = 0;//最⼤值
if (!lowerPoint.isEmpty() && !upperPoint.isEmpty()) {
lowerEndpoint = Math.abs(Long.parseLong(lowerPoint));
lupperEndpoint = Math.abs(Long.parseLong(upperPoint));
} else if (lowerPoint.isEmpty() && !upperPoint.isEmpty()) {
lupperEndpoint = Math.abs(Long.parseLong(upperPoint));
lowerEndpoint = 0;
} else if (!lowerPoint.isEmpty() && upperPoint.isEmpty()) {
lowerEndpoint = Math.abs(Long.parseLong(lowerPoint));
lupperEndpoint = 40;
}
// 循环范围计算分库逻辑
for (long i = lowerEndpoint; i <= lupperEndpoint; i++) {
for (String db : dbNames) {
if (db.endsWith(i % dbNames.size() + "")) {
collect.add(db);
}
}
}
return collect;
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论