- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Sharding-Jdbc 自定义复合分片的实现(分库分表)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
Sharding-JDBC中的分片策略有两个维度,分别是:
其中,数据源分片策略表示:数据路由到的物理目标数据源,表分片策略表示数据被路由到的目标表.
特别的,表分片策略是依赖于数据源分片策略的,也就是说要先分库再分表,当然也可以只分表.
Sharding-JDBC的分片策略包含了分片键和分片算法。由于分片算法与业务实现紧密相关,因此Sharding-JDBC没有提供内置的分片算法,而是通过分片策略将各种场景提炼出来,提供了高层级的抽象,通过提供接口让开发者自行实现分片算法.
以下内容引用自官方文档。官方文档 。
首先介绍四种分片算法.
通过分片算法将数据分片,支持通过=、BETWEEN和IN分片。 分片算法需要应用方开发者自行实现,可实现的灵活度非常高.
目前提供4种分片算法。由于分片算法和业务实现紧密相关, 因此并未提供内置分片算法,而是通过分片策略将各种场景提炼出来, 提供更高层级的抽象,并提供接口让应用开发者自行实现分片算法.
用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。 SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,ShardingSphere也支持根据多个字段进行分片.
通过分片算法将数据分片,支持通过=、BETWEEN和IN分片。分片算法需要应用方开发者自行实现,可实现的灵活度非常高.
目前提供4种分片算法。由于分片算法和业务实现紧密相关,因此并未提供内置分片算法,而是通过分片策略将各种场景提炼出来,提供更高层级的抽象,并提供接口让应用开发者自行实现分片算法.
精确分片算法 。
对应PreciseShardingAlgorithm,用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用.
范围分片算法 。
对应RangeShardingAlgorithm,用于处理使用单一键作为分片键的BETWEEN AND进行分片的场景。需要配合StandardShardingStrategy使用.
复合分片算法 。
对应ComplexKeysShardingAlgorithm,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用.
Hint分片算法 。
对应HintShardingAlgorithm,用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用.
包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。目前提供5种分片策略.
标准分片策略 。
对应StandardShardingStrategy。提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。RangeShardingAlgorithm是可选的,用于处理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理.
复合分片策略 。
对应ComplexShardingStrategy。复合分片策略。提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度.
行表达式分片策略 。
对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如:t_user_$->{u_id % 8}表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0到t_user_7.
Hint分片策略 。
对应HintShardingStrategy。通过Hint而非SQL解析的方式分片的策略.
不分片策略 。
对应NoneShardingStrategy。不分片的策略.
对于分片字段非SQL决定,而由其他外置条件决定的场景,可使用SQL Hint灵活的注入分片字段。例:内部系统,按照员工登录主键分库,而数据库中并无此字段。SQL Hint支持通过Java API和SQL注释(待实现)两种方式使用.
由于目的为贴近实战,因此着重讲解如何实现复杂分片策略,即实现ComplexShardingStrategy接口定制生产可用的分片策略.
AdminIdShardingAlgorithm 复合分片算法代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
import
com.google.common.collect.Range;
import
io.shardingjdbc.core.api.algorithm.sharding.ListShardingValue;
import
io.shardingjdbc.core.api.algorithm.sharding.PreciseShardingValue;
import
io.shardingjdbc.core.api.algorithm.sharding.RangeShardingValue;
import
io.shardingjdbc.core.api.algorithm.sharding.ShardingValue;
import
io.shardingjdbc.core.api.algorithm.sharding.complex.ComplexKeysShardingAlgorithm;
import
org.apache.commons.lang.StringUtils;
import
org.apache.log4j.Logger;
import
java.util.*;
/**
*/
public
class
AdminIdShardingAlgorithm
implements
ComplexKeysShardingAlgorithm {
private
Logger logger = Logger.getLogger(getClass());
@Override
public
Collection<String> doSharding(Collection<String> availableTargetNames, Collection<ShardingValue> shardingValues) {
Collection<String> routTables =
new
HashSet<String>();
if
(shardingValues !=
null
) {
for
(ShardingValue shardingValue : shardingValues) {
// eq in 条件
if
(shardingValue
instanceof
ListShardingValue) {
ListShardingValue listShardingValue = (ListShardingValue) shardingValue;
Collection<Comparable> values = listShardingValue.getValues();
if
(values !=
null
) {
Iterator<Comparable> it = values.iterator();
while
(it.hasNext()) {
Comparable value = it.next();
String routTable = getRoutTable(shardingValue.getLogicTableName(), value);
if
(StringUtils.isNotBlank(routTable)) {
routTables.add(routTable);
}
}
}
// eq 条件
}
else
if
(shardingValue
instanceof
PreciseShardingValue) {
PreciseShardingValue preciseShardingValue = (PreciseShardingValue) shardingValue;
Comparable value = preciseShardingValue.getValue();
String routTable = getRoutTable(shardingValue.getLogicTableName(), value);
if
(StringUtils.isNotBlank(routTable)) {
routTables.add(routTable);
}
// between 条件
}
else
if
(shardingValue
instanceof
RangeShardingValue) {
RangeShardingValue rangeShardingValue = (RangeShardingValue) shardingValue;
Range<Comparable> valueRange = rangeShardingValue.getValueRange();
Comparable lowerEnd = valueRange.lowerEndpoint();
Comparable upperEnd = valueRange.upperEndpoint();
Collection<String> tables = getRoutTables(shardingValue.getLogicTableName(), lowerEnd, upperEnd);
if
(tables !=
null
&& tables.size() >
0
) {
routTables.addAll(tables);
}
}
if
(routTables !=
null
&& routTables.size() >
0
) {
return
routTables;
}
}
}
throw
new
UnsupportedOperationException();
}
private
String getRoutTable(String logicTable, Comparable keyValue) {
Map<String, List<KeyShardingRange>> keyRangeMap = KeyShardingRangeConfig.getKeyRangeMap();
List<KeyShardingRange> keyShardingRanges = keyRangeMap.get(KeyShardingRangeConfig.SHARDING_ID_KEY);
if
(keyValue !=
null
&& keyShardingRanges !=
null
) {
if
(keyValue
instanceof
Integer) {
keyValue = Long.valueOf(((Integer) keyValue).intValue());
}
for
(KeyShardingRange range : keyShardingRanges) {
if
(keyValue.compareTo(range.getMin()) >=
0
&& keyValue.compareTo(range.getMax()) <=
0
) {
return
logicTable + range.getTableKey();
}
}
}
return
null
;
}
private
Collection<String> getRoutTables(String logicTable, Comparable lowerEnd, Comparable upperEnd) {
Map<String, List<KeyShardingRange>> keyRangeMap = KeyShardingRangeConfig.getKeyRangeMap();
List<KeyShardingRange> keyShardingRanges = keyRangeMap.get(KeyShardingRangeConfig.SHARDING_CONTENT_ID_KEY);
Set<String> routTables =
new
HashSet<String>();
if
(lowerEnd !=
null
&& upperEnd !=
null
&& keyShardingRanges !=
null
) {
if
(lowerEnd
instanceof
Integer) {
lowerEnd = Long.valueOf(((Integer) lowerEnd).intValue());
}
if
(upperEnd
instanceof
Integer) {
upperEnd = Long.valueOf(((Integer) upperEnd).intValue());
}
boolean
start =
false
;
for
(KeyShardingRange range : keyShardingRanges) {
if
(lowerEnd.compareTo(range.getMin()) >=
0
&& lowerEnd.compareTo(range.getMax()) <=
0
) {
start =
true
;
}
if
(start) {
routTables.add(logicTable + range.getTableKey());
}
if
(upperEnd.compareTo(range.getMin()) >=
0
&& upperEnd.compareTo(range.getMax()) <=
0
) {
break
;
}
}
}
return
routTables;
}
}
|
范围 map 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
import
java.util.ArrayList;
import
java.util.LinkedHashMap;
import
java.util.List;
import
java.util.Map;
/**
* 分片键分布配置
*/
public
class
KeyShardingRangeConfig {
private
static
Map<String, List<KeyShardingRange>> keyRangeMap =
new
LinkedHashMap<String, List<KeyShardingRange>>();
public
static
final
String SHARDING_ORDER_ID_KEY =
"id"
;
public
static
final
String SHARDING_USER_ID_KEY =
"adminId"
;
public
static
final
String SHARDING_DATE_KEY =
"createTime"
;
static
{
List<KeyShardingRange> idRanges =
new
ArrayList<KeyShardingRange>();
idRanges.add(
new
KeyShardingRange(
0
,
"_0"
, 0L, 4000000L));
idRanges.add(
new
KeyShardingRange(
1
,
"_1"
, 4000001L, 8000000L));
idRanges.add(
new
KeyShardingRange(
2
,
"_2"
, 8000001L, 12000000L));
idRanges.add(
new
KeyShardingRange(
3
,
"_3"
, 12000001L, 16000000L));
idRanges.add(
new
KeyShardingRange(
4
,
"_4"
, 16000001L, 2000000L));
keyRangeMap.put(SHARDING_ID_KEY, idRanges);
List<KeyShardingRange> contentIdRanges =
new
ArrayList<KeyShardingRange>();
contentIdRanges.add(
new
KeyShardingRange(
0
,
"_0"
, 0L, 4000000L));
contentIdRanges.add(
new
KeyShardingRange(
1
,
"_1"
, 4000001L, 8000000L));
contentIdRanges.add(
new
KeyShardingRange(
2
,
"_2"
, 8000001L, 12000000L));
contentIdRanges.add(
new
KeyShardingRange(
3
,
"_3"
, 12000001L, 16000000L));
contentIdRanges.add(
new
KeyShardingRange(
4
,
"_4"
, 16000001L, 2000000L));
keyRangeMap.put(SHARDING_CONTENT_ID_KEY, contentIdRanges);
List<KeyShardingRange> timeRanges =
new
ArrayList<KeyShardingRange>();
timeRanges.add(
new
KeyShardingRange(
"_0"
, 20170701L, 20171231L));
timeRanges.add(
new
KeyShardingRange(
"_1"
, 20180101L, 20180630L));
timeRanges.add(
new
KeyShardingRange(
"_2"
, 20180701L, 20181231L));
timeRanges.add(
new
KeyShardingRange(
"_3"
, 20190101L, 20190630L));
timeRanges.add(
new
KeyShardingRange(
"_4"
, 20190701L, 20191231L));
keyRangeMap.put(SHARDING_DATE_KEY, timeRanges);
}
public
static
Map<String, List<KeyShardingRange>> getKeyRangeMap() {
return
keyRangeMap;
}
}
|
核心逻辑解析 。
梳理一下逻辑,首先介绍一下该方法的入参 。
参数名 解释 。
availableTargetNames 有效的物理数据源,即配置文件中的 t_order_0,t_order_1,t_order_2,t_order_3 。
shardingValues 分片属性,如:{“columnName”:”order_id”,”logicTableName”:”t_order”,”values”:[“UD020003011903261545436593200002”]} ,包含:分片列名,逻辑表名,当前列的具体分片值 。
该方法返回值为 。
参数名 解释 。
Collection<String> 分片结果,可以是目标数据源,也可以是目标数据表,此处为数据源 。
接着回来看业务逻辑,伪代码如下 。
首先打印了一下数据源集合 availableTargetNames 以及 分片属性 shardingValues的值,执行测试用例后,日志输出为:
1
2
3
|
availableTargetNames:["t_order_0","t_order_1","t_order_2","t_order_3"],
shardingValues:[{"columnName":"user_id","logicTableName":"t_order","values":["UD020003011903261545436593200002"]},
{"columnName":"order_id","logicTableName":"t_order","values":["OD000000011903261545475143200001"]}]
|
从日志可以看出,我们可以在该路由方法中取到配置时的物理数据源列表,以及在运行时获取本次执行时的路由属性及其值 。
完整的逻辑流程如下:
本文中,基本完成了Sharding-JDBC中复合分片路由算法的自定义实现,并经过测试验证符合预期,该实现方案在生产上已经经历过考验。定义分片路由策略的核心还是要熟悉ComplexKeysShardingAlgorithm,对如何解析 doSharding(CollectionavailableTargetNames, CollectionshardingValues)的参数有明确的认识,最简单的方法就是实际打印一下参数,相信会让你更加直观的感受到作者优良的接口设计能力,站在巨人的肩膀上我们能看到更远.
到此这篇关于Sharding-Jdbc 自定义复合分片的实现的文章就介绍到这了,更多相关Sharding-Jdbc 自定义复合分片内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://www.cnblogs.com/rinack/p/11241111.html 。
最后此篇关于Sharding-Jdbc 自定义复合分片的实现(分库分表)的文章就讲到这里了,如果你想了解更多关于Sharding-Jdbc 自定义复合分片的实现(分库分表)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在实现一个显示容器级别的图表。根据填充水平,线条的颜色应该改变(例如,接近最大值时应该显示红色)。我不想计算线条的不同部分并手动设置它们的颜色,而是想定义一个颜色自动改变的带。我想用自定义 Com
#include int main(void) { int days, hours, mins; float a, b, c, total, temp, tempA, tempB; a
if()//first if { if()//second if statement; } else statement; 我知道 else 与第一个 if 匹配,但我的问题是为什么?我是
以下代码中测试了 Ready 的哪个实例,为什么? interface type TObject1 = class ... public property Ready: boole
我刚刚花了相当多的时间来寻找像这个 plunk 中的差距.问题没那么简单。这是一个动态创建的页面,一些具有 margin-bottom 的组件恰好显示在 .main 的最后。 在我指责 CSS 之前,
我的程序应该在对话中创建圆形图标。我有三个按钮,每个按钮代表要制作的图标的颜色。因此,如果我点击不同的按钮 10 次,我的程序应该创建 10 个不同颜色的圆圈。这是我的代码,分为 2 个类: impo
我读过; A compound literal is a C99 feature that can be used to create an array with no name. Consider
当您创建一个复合 View 并为其扩充 xml 布局文件时,如下所示: public class CompundLayout extends LinearLayout{...} 这会像这样用根扩展一个
我正在创建一个带有标签和文本框的复合 uibinder 小部件。 预期用途是: The text to be put in the box. 我找到了如何使用自定义 @UiConstruc
任何人都可以举一个结合使用设计模式组合和责任链的实际例子吗? 谢谢 最佳答案 一个非常实际的例子是 GUI 设计,例如 Qt 框架。 QObject 可以是单个对象或多个对象的组合。 QObjects
我在这个项目中的一些表单中使用了复合 View 模型的模式。它工作得很好。 在这种情况下,我有一个 VendorAddress View 模型。我在这个项目的几个地方使用了 Address(es),所
我正在尝试构建一个我认为需要多个 JOIN 的 SQL 查询,但我不知道语法。 这是每个表(带有列名)的粗略示例。 T1( key ,名称) T2(键,fkeyT1) T3(键,fkeyT2) 我想从
我有一个 Composite我希望能够以编程方式启用/禁用。 Control.setEnabled(boolean enabled)方法工作正常,但它没有提供任何小部件被禁用的视觉信息。 我想做的是让
如果子域不是“mobile”并且文件名不是“design”或“photo”,我想回显某些内容,因此 echo if (not“mobile”且不是“design”)或(not“mobile”而不是“照
我有一张有几列的 table 。第 1 列和第 2 列可以包含四个 alpha 值中的任何一个:set={A,B,C,D}。 我想检查每列是否包含集合中的两个值之一。所以我想简化这个陈述: SELEC
我创建了一个全局数据类型,并在页面中使用表单渲染器让用户填写数据并提交到网站。 默认的英语工作正常。现在,当我尝试支持第二种语言时,我遇到了问题。根据复合文档: 1.在 ~/Frontend/Comp
我需要将自定义对象作为值存储在字典中,例如具有两个复合整数键的 datastrukturer。 (复合 ID) 我尝试使用数组作为键,但两者都不起作用,因为我猜这只是指向该数组的指针,用作键 如果我能
版本:3.2.1 关系 表B中的两列与表A中的两列相关联。 表A-> hasMany->表B 表B->属于--表A B.a_id = A.a_id B.a_name = A.a_name 食谱 在食谱
我创建了一个全局数据类型,并在页面中使用表单渲染器让用户填写数据并提交到网站。 默认的英语工作正常。现在,当我尝试支持第二种语言时,我遇到了问题。根据复合文档: 1.在 ~/Frontend/Comp
当前版本的 Log4net 是否有办法创建具有复合滚动样式的 RollingFileAppender,其中滚动文件始终保留给定的扩展名(在我的情况下为 .log)? 我想要的格式示例: MyLog.l
我是一名优秀的程序员,十分优秀!