mysql、oracle分库分表⽅案之sharding-jdbc使⽤(⾮demo⽰例)
选择开源核⼼组件的⼀个⾮常重要的考虑通常是社区活跃性,⼀旦项⽬团队⽆法进⾏⾃⼰后续维护和扩展的情况下更是如此。
⾄于为什么选择sharding-jdbc⽽不是Mycat,可以参考知乎讨论帖⼦www.zhihu/question/64709787。
还可以参考blog.csdn/u013898617/article/details/79615427。
关于分库分表和读写分离、主从
⼀般来说,需要分库分表的系统是流量⽐较⼤的,⽽且⽐较容易出现峰值的⽐如说打折/活动的时候;其次,当单机扛不住业务流量的时候,分库分表⼀定不是第⼀选择,在分库分表之前,应该先保证垂直拆分完成了,⼦系统内都是⾼内聚的,其次基于Master-Slave的读写分离或者模糊查询很多的,可能NoSQL⽐如elastic就引流去很⼤⼀部分了。当读写分离也做完了,主库只剩下关键业务逻辑之后,流量还是很⾼,这个时候才开始考虑分库分表。因为相对于读写分离、垂直拆分,分库分表对开发和运维的要求多得多,如果确定业务⼀两年内不会剧增的,盲⽬引⼊只会导致成本⾼昂(尤其是各种SQL限制)。
其次,分库分表会增加N倍的数据库服务器,⼀般来说是4的倍数,如果某个应⽤说要做分库分表,⼜只有
两台机器,那完全就是凑热闹。
读写分离和分库分表应该来说是前后的两件事⽐较合理,不少⼈将这两个事情混到⼀起去讲准确的说不合理的。分库分表通常更多的是⽤于纯粹的OLTP的事情,让系统可以⽔平扩展。⽽读写分离更多的是为了把⼀部分可以容忍短时延迟/不保证100%(但应该在99%以上)准确的查询路由到查询库,准确的说是对业务根据优先级做个归类,这些查询从资源消耗的⾓度来说相对逻辑上的PK查询要⾼⼏倍到数百倍,⽐如说查询某个⼈过去3个⽉的交易情况,但他从业务⾓度并不算是DSS概念,⽐如说查询已经T-N的订单/针对这些订单进⾏导出,并针对这个单⼦可能会进⾏⼀些操作,甚⾄⼈⼯修改状态。通过把这些功能从核⼼的订单/交易/资⾦OLTP中拆分出去,可以保证核⼼业务系统不会因为⼀个异常操作⽐如SQL不合理导致系统出现业务负载增加外的额外抖动因素。
从系统设计⾓度来说,读写分离虽然从逻辑表结构⾓度来说是相同的,都具有相同的字段定义,但是物理实现上是⼀定是不相同(要是完全相同,说明没有领会读写分离的初衷)的,尤其是在索引上,写库可能除了PK、唯⼀索引(任何表都应该有唯⼀索引,分布式锁只能作为缓冲器)外,最多还有⼀两个简单的字段索引以最⼤化性能,任何SQL符合条件的数据⼀般不会超过⼏⼗条(极端客户除外),但是读库根据业务不同,可能会有很多的索引以满⾜各种查询以及简单的统计汇总报表的需求。
那写库是不是⼀定就⽐读库重要呢?是,⼜不是。是是绝对的,不是是相对的。因为读库不是DSS库,
是交易库中相对来说不是特别重要的业务功能。所以,写库⼀旦挂了,就会导致业务下不去,读库挂了,可能会导致做业务的⼈决策错误。⽐如没有没有查到做过某交易,⼜重新交易⼀次。
考虑分库分表⼀个很重要的决策就是是否允许跨多库操作以及有没有必要。TODO。。。。待补充。。。。。。
其次,分库和分表是两件事,是到底选择分库还是分表,如果量没有那么⼤的话⽽且是虚拟机的话,估计分库就够了。
sharding-jdbc的版本及其架构差异
⽬前最新版本的sharding-jdbc是v3.0.0.M1,应该来说还不稳定,包名⼜改成了io.shardingsphere,jar包名是sharding-jdbc。
1.5.4.1是⽬前最新版,也可能是终版,1.x的,坐标是com.dangdang,jar包名是sharding-jdbc。
2.0.3是⽬前最新版,包名和坐标统⼀改成了io.shardingjdbc,jar包名是sharding-jdbc-core。
说明规划不是特别好,还是有些乱。
因为2.0之后基本上纯粹分库分表的核⼼特性的增强就不多了,主要往治理和代理⽅向去了,所以如果没有特别的需求⽐如需要类似mycat的独⽴服务代理模式,使⽤1.x(注:1.x版本官⽹⽂档好像下线了)就可以了,不过如果是⼤规模的部署,同时已经使⽤了微服务架构中的注册中⼼或者基于spring boot,可以考虑使⽤2.0,因为2.0增加了基于注册中⼼的配置管理以及spring boot starter。所以2.0的架构是这样的:
3.0之后,增加了类似mycat⾓⾊的sharding-proxy⽆状态服务器(代理层可以有,但是不应该作为应⽤直接访问的⼊⼝,如下图所⽰),以及类似于Service Mesh的Database Mesh。不过核⼼没有变化,对SQL语法增加了部分新的⽀持。所以3.0的架构如下:
就分库分表核⼼来说,我们就只要关⼼sharding-jdbc就可以了,不需要关⼼sharding-sphere的其他部分。
sharding-jdbc/Sharding-Proxy/Sharding-Sidecar三者的对⽐如下:
核⼼特性
事务
对任何重要的系统来说,事务⼀致性都是关键的。对分布式系统来说更是如此,最重要的就是事务⼀致性,从这个层⾯来说,分库分表本⾝并没有引⼊另外⼀个层次的复杂性。因为它在jdbc驱动层包了⼀层,所以我们有必要理解它对事务的⽀持性以及相关的限制。事务
sharding jdbc 2.x不⽀持强⼀致性的分布式事务,⼀般现在的系统设计也不追求强⼀致性,⽽是最终⼀致性。所以sharding jdbc 2.x⽀持2中事务:弱XA(同mycat)和最⼤努⼒投递事务(官⽅简称BED)(算是BASE的⼀种),具体选择哪⼀种需要根据业务和开发进⾏权衡,如果架构规范和设计做得好,是可以做到不跨库分布式事务的。
弱XA事务是默认的模式(即只要dml期间没有抛出异常,commit期间有机器断⽹或者宕机,是⽆法保证⼀致性的),没有特别的要求。
BED则在⼀定上增加了短时容忍,将执⾏的语句另作中⼼化存储,然后轮询commit期间失败的事务重试,所以BED的架构如下:
但是没有免费的午餐,BED对开发和维护有着⼀定的额外要求,⽽且这些要求都涉及⾯很⼴,绝对算得
上伤筋动⾻。开发层⾯包括:
1. INSERT语句的主键不能⾃增
2. UPDATE必须可重复执⾏,⽐如不⽀持UPDATE xxx SET x=x+1,对于更新余额类,这就相当于要求必须乐观锁了
运维层⾯包括:
1. 需要存储事务⽇志的数据库
2. ⽤于异步作业使⽤的zookeeper
3. 解压sharding-jdbc-transaction-async-job-$VERSION.tar,通过start.sh脚本启动异步作业
我们选择了从设计层⾯避免强⼀致性的分布式事务。
分⽚灵活性
对于分库分表来说,很重要的⼀个特性是分⽚的灵活性,⽐如单个字段、多个字段的=、IN、>=、<=。为什么多个字段很重要的,这⾥涉及到⼀个特殊的考虑
sharding-jdbc⽬前提供4种分⽚算法。
由于分⽚算法和业务实现紧密相关,因此并未提供内置分⽚算法,⽽是通过分⽚策略将各种场景提炼出来,提供更⾼层级的抽象,并提供接⼝让应⽤开发者⾃⾏实现分⽚算法。
精确分⽚算法
对应PreciseShardingAlgorithm,⽤于处理使⽤单⼀键作为分⽚键的=与IN进⾏分⽚的场景。需要配合StandardShardingStrategy使⽤。
范围分⽚算法
jdbc连接oracle对应RangeShardingAlgorithm,⽤于处理使⽤单⼀键作为分⽚键的BETWEEN AND进⾏分⽚的场景。需要配合StandardShardingStrategy使⽤。
复合分⽚算法
对应ComplexKeysShardingAlgorithm,⽤于处理使⽤多键作为分⽚键进⾏分⽚的场景,多分⽚键逻辑较复杂,需要应⽤开发者⾃⾏处理其中的复杂度。需要配合ComplexShardingStrategy使⽤。
Hint分⽚算法(Hint分⽚指的是对于分⽚字段⾮SQL决定,⽽由其他外置条件决定的场景,可使⽤SQL Hint灵活的注⼊分⽚字段。例:内部系统,按照员⼯登录ID分库,⽽数据库中并⽆此字段。SQL Hint⽀持通过Java API和SQL注释(待实现)两种⽅式使⽤。)
对应HintShardingAlgorithm,⽤于处理使⽤Hint⾏分⽚的场景。需要配合HintShardingStrategy使⽤。
因为算法的灵活性,标准的⽅式是通过实现具体的java接⼝是实现具体的分⽚算法⽐如SingleKeyDatabaseShardingAlgorithm,有不少的情况下,分⽚是⽐较简单的,⽐如说纯粹是客户编号,此时提供了⾏内表达式分⽚策略,使⽤Groovy的表达式,提供对SQL语句中的=和IN的分⽚操作⽀持,不过这只⽀持单分⽚键。⽐如,t_user_${u_id % 8}表⽰
t_user表按照u_id按8取模分成8个表,表名称为t_user_0到t_user_7。
分⽚键+分⽚算法=真正可⽤的分⽚策略。
算法和分⽚键的选择是分库分表的关键,其直接决定了各个分库的负载是否均衡,以及扩展是否容易。在设计上的考虑⼀节笔者会详细阐述,订单和委托业务、⽤户在使⽤分库分表时设计上的考虑以及原因。
SQL语法限制
对于分库分表来说,还需要知道有哪些SQL的限制,尤其是涉及到需要⼆次处理的,⽐如排序,去重,聚合等。
这⾥笔者就列下那些常⽤但没有被⽀持的。⽐如:
case when
distinct
union
不过好在这些在java/js中处理都⽐较⽅便。
如果有很复杂的SQL,那最⼤的可能就是设计上有问题,应该采⽤读写分离解决。
sharding-jdbc对SQL的限制完整可以参考shardingsphere.io/document/current/cn/features/sharding/usage-standard/sql/
设计上的考虑
哪些表要分库分表
⾸先从设计上要区分清楚哪些是⼴播表/哪些是分库表/哪些是只在⼀个库的全局表,因为是公⽤数据源的,所以不管是不是分库的表,都需要配置,不配置分⽚规则Sharding-JDB即⽆法精确的断定应该路由⾄哪个数据源。但是⼀般分库分表组件包括Sharding-JDBC都会提供简化配置的⽅法。对于不分⽚的表:
⽅法1:sharding-jdbc可以在<sharding:sharding-rule />配置default-data-source-name,这样未配置分⽚规则的表将通过默认数据源定位。
⽅法2:将不参与分库分表的数据源独⽴于Sharding-JDBC之外,在应⽤中使⽤多个数据源分别处理分⽚和不分⽚的情况。
分库还是分表
⼀般来说应该选择分库(准确的说是分schema),不应该使⽤分表,因为oracle可以包含n个schema,mysql可以包含多个database,⽽且就算真的需要,schema之间也是可以关联查询的,所以感觉就算是为了扩展性问题,也没有必要使⽤分表,分表反⽽在扩展的时候更加⿇烦。就算数据量多了⼀点,感觉稍微偏慢,可以先采⽤分区挡⼀挡。
分⽚键的选择
其中最重要的是分⽚键不能是⾃增字段,否则insert就不知道去哪⾥了。所以对于ID⽣成,需要⼀个ID⽣成中⼼。
分布式主键
分布式系统的主键⽣成可以通过设置增量或者也通过ID⽣成中⼼来⽣成,不过话说回来,既然使⽤ID⽣成中⼼了,就不要再使⽤数据库机制的ID了,这不⼀定需要通过代码全部重写,可以在dao层通过aop判断是否insert,是Insert的动态从ID中⼼获取,这样就避免了分库分表和⾮分库分表在开发商的差别。
Sharding-JDBC使⽤说明
对于只有⼀个分⽚键的使⽤=和IN进⾏分⽚的SQL,建议使⽤⾏表达式代替Java类的配置。假设我们不使⽤弱性事务(如果使⽤柔性事务,则还需要引⼊sharding-jdbc-transaction以及sharding-jdbc-transaction-async-job),这样就只要引⼊sharding-jdbc-core这个jar包就可以了,(因为sharding-jdbc的配置⽀持java、yaml、spring boot以及spring命名空间(类似dubbo),所以建议使⽤spring 命名空间⽅式)如下:
<dependency>
<groupId>io.shardingjdbc</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>2.0.3</version>
</dependency>
<!-- for sharding-jdbc spring namespace -->
<dependency>
<groupId>io.shardingjdbc</groupId>
<artifactId>sharding-jdbc-core-spring-namespace</artifactId>
<version>2.0.3</version>
</dependency>
因为sharding jdbc可以⽀持dbcp、druid,所以就不⽤改动其他的依赖项了。
接下去配置数据源、数据源分⽚策略和表分⽚策略。
我们假设分库结构(此处2个库仅做演⽰⽬的,实际应该⾄少4个分库)如下:
order和order_item通过order_id关联,且分⽚规则相同。
分库1和分库2通过user_id作为分⽚字段,采⽤取模(采⽤取模⽽不是区间的好处是负载从理论上最均衡,⽤区间其实是不均衡的,⽐如假设客户⽐较稳定,就1000万,0-100万第⼀个分⽚,以此类推,实际上还是可能很不均衡,因为某段时间增加的客户可能会特别活跃,尤其是在互联⽹应⽤中)
配置三个数据源:
1、globalDataSource,指向全局库,⾮分库分表和⼴播的表,⽐如系统参数;
2、dataSource_0、dataSource_1,指向分库1和分库2;
<bean name="dataSource_0" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url_0}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- 配置初始化⼤⼩、最⼩、最⼤ -->
<property name="initialSize" value="${jdbc.initialSize}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${jdbc.maxWait}"/>
<!-- 打开PSCache,并且指定每个连接上PSCache的⼤⼩ -->
<property name="poolPreparedStatements" value="${jdbc.pps}"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="${jdbc.mpps}"/>
<!-- 配置间隔多久才进⾏⼀次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
<!-- 配置⼀个连接在池中最⼩⽣存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
<property name="removeAbandoned" value="${veAbandoned}"/>
<property name="removeAbandonedTimeout" value="${veAbandonedTimeout}"/>
<property name="logAbandoned" value="${jdbc.logAbandoned}"/>
<!-- 配置监控统计拦截的filters -->
<property name="filters" value="${jdbc.filters}"/>
</bean>
<bean name="dataSource_1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url_1}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- 配置初始化⼤⼩、最⼩、最⼤ -->
<property name="initialSize" value="${jdbc.initialSize}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${jdbc.maxWait}"/>
<!-- 打开PSCache,并且指定每个连接上PSCache的⼤⼩ -->
<property name="poolPreparedStatements" value="${jdbc.pps}"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="${jdbc.mpps}"/>
<!-- 配置间隔多久才进⾏⼀次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
<!-- 配置⼀个连接在池中最⼩⽣存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
<property name="removeAbandoned" value="${veAbandoned}"/>
<property name="removeAbandonedTimeout" value="${veAbandonedTimeout}"/>
<property name="logAbandoned" value="${jdbc.logAbandoned}"/>
<!-- 配置监控统计拦截的filters -->
<property name="filters" value="${jdbc.filters}"/>
</bean>
<bean name="globalDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- 配置初始化⼤⼩、最⼩、最⼤ -->
<property name="initialSize" value="${jdbc.initialSize}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${jdbc.maxWait}"/>
<!-- 打开PSCache,并且指定每个连接上PSCache的⼤⼩ -->
<property name="poolPreparedStatements" value="${jdbc.pps}"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="${jdbc.mpps}"/>
<!-- 配置间隔多久才进⾏⼀次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
<!-- 配置⼀个连接在池中最⼩⽣存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
<property name="removeAbandoned" value="${veAbandoned}"/>
<property name="removeAbandonedTimeout" value="${veAbandonedTimeout}"/>
<property name="logAbandoned" value="${jdbc.logAbandoned}"/>
<!-- 配置监控统计拦截的filters -->
<property name="filters" value="${jdbc.filters}"/>
</bean>
全局表、分库不分表、分库分表、⼴播表、主、⼦表绑定的各⾃规则配置(下⾯使⽤⾏内策略,注:blog.csdn/shijiemozujiejie/article/details/80786231提到⾏表达式
的策略不利于数据库和表的横向扩展,这是有道理的,因为java代码我们可以随时重新加载分库和分表的基数,做到不停机扩展,但是⾏内表达式不⾏)如下:
<!-- 必须加上ignore-unresolvable,否则很可能会出现java.lang.IllegalArgumentException: Could not resolve placeholder以及cannot invoke method mod() on null object-->
<context:property-placeholder location="classpath:jrescloud.properties" ignore-unresolvable="true" order="1"/>
<!-- 分库策略,尽量使⽤sharding:standard-strategy⽽不是inline-stragegy -->
<sharding:inline-strategy id="databaseStrategy" sharding-column="user_id" algorithm-expression="dataSource_${user_id % 2}"/>
<!-- 分表策略 -->
<sharding:inline-strategy id="orderTableStrategy" sharding-column="order_id" algorithm-expression="t_order_${order_id % 2}"/>
<sharding:inline-strategy id="orderItemTableStrategy" sharding-column="order_id" algorithm-expression="t_order_item_${order_id % 2}"/>
<sharding:data-source id="shardingDataSource">
<!-- configDataSource为不参数分库分表的全局表的默认数据源,⽐如系统参数 -->
<sharding:sharding-rule data-source-names="dataSource_0,dataSource_1,globalDataSource" default-data-source-name="globalDataSource">
<sharding:table-rules>
<!-- 分库+分表 -->
<sharding:table-rule logic-table="t_order" actual-data-nodes="dataSource_${0..1}.t_order_${0..1}" database-strategy-ref="databaseStrategy" table-strategy-ref="orderTableStrategy"/>
<sharding:table-rule logic-table="t_order_item" actual-data-nodes="dataSource_${0..1}.t_order_item_${0..1}" database-strategy-ref="databaseStrategy" table-strategy-ref="orderItemTableStrategy" />
<!-- 分库不分表 -->
<sharding:table-rule logic-table="t_order" database-strategy-ref="databaseStrategy"/>
<!-- ⼴播表 -->
<sharding:table-rule logic-table="t_dict"/>
</sharding:table-rules>
<!-- 绑定表规则列表,表⽰分库分表的规则相同,这样万⼀涉及到多个分⽚的查询,sharding-jdbc就可以确定分库之间不需要不必要的⼆次关联,所有的查询都应该如此 -->
<sharding:binding-table-rules>
<sharding:binding-table-rule logic-tables="t_order,t_order_item"/>
</sharding:binding-table-rules>
</sharding:sharding-rule>
</sharding:data-source>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="shardingDataSource"/>
</bean>
<!-- 使⽤annotation ⾃动注册bean, 并保证@Required、@Autowired的属性被注⼊ -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sqlSessionFactory" class="batis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="l"/>
<property name="dataSource" ref="shardingDataSource"/>
<property name="mapperLocations">
<list>
<value>classpath*:sqlmap/com/yidoo/k3c/**/*.xml</value>
</list>
</property>
</bean>
HINT分⽚策略的使⽤
Hint分⽚指的是对于分⽚字段⾮SQL决定,⽽由其他外置条件决定的场景,可使⽤SQL Hint灵活的注⼊分⽚字段。举个实例的例⼦,我们都知道mysql insert values相对于循环插
⼊来说,性能差距基本上可以说是⽹络延时的倍数,⽐如说插⼊1000条记录,⽹络来回1ms,1000条就得1m,如果是跨⽹段的,延时就更长了。⽽sharding-jdbc和Mycat都不⽀
持多values(sharding-jdbc 3.x⽀持,但还没有正式发布),有些SQL语句⽐较复杂⽐如说有(a = var or b = var) and member_id = N,这个时候druid sqlparser并不⽀持的时候,
虽然可以通过多数据源解决,但是我们不希望架构搞得太复杂,这种情况下,可以通过sharding-jdbc的Hint分⽚策略来实现各种sharding-jdbc不⽀持的语法的限制。因为Hint分
⽚策略是绕过SQL解析的,所以对于这些⽐较复杂的需要分⽚的⾮DSS查询,采⽤Hint分⽚策略性能可能会更好。同样,我们还是使⽤mybatis作为数据库访问层作为例⼦,对于
Hint分⽚策略,帖⼦⼤都是基于1.x版本进⾏源码分析路由,顺带提及,基本上都是瞎扯,同时在⽤法上sharding-jdbc-example没有提及。因为我们实际要⽤,所以笔者基于2.0.3
版本进⾏了完整的测试确保结果符合我们的预期。
⾸先定义⼀个hint策略,hint策略需要实现api.algorithm.sharding.hint.HintShardingAlgorithm接⼝。
<sharding:hint-strategy id="hintDatabaseStrategy" algorithm-class="ute.hint.HintShardingAlgorithm"/>
package ute.hint;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.druid.util.StringUtils;
import com.yidoo.utils.JacksonHelper;
import api.algorithm.sharding.ListShardingValue;
import api.algorithm.sharding.ShardingValue;
public class HintShardingAlgorithm implements api.algorithm.sharding.hint.HintShardingAlgorithm {
private static final Logger logger = Logger(HintShardingAlgorithm.class);
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, ShardingValue shardingValue) {
logger.debug("shardingValue=" + JSON(shardingValue));
logger.debug("availableTargetNames=" + JSON(availableTargetNames));
List<String> shardingResult = new ArrayList<>();
availableTargetNames.forEach(targetName -> {
String suffix = targetName.substring(targetName.lastIndexOf("_")+1);
if(StringUtils.isNumber(suffix)) {
// hint分⽚算法的ShardingValue有两种具体类型: ListShardingValue和RangeShardingValue,取决于api.HintManager.addDatabaseShardingValue(String, String, ShardingOperator, Comparable<?>...)的时候,ShardingO ListShardingValue<Integer> tmpSharding = (ListShardingValue<Integer>) shardingValue;
if (value % 2 == Integer.parseInt(suffix)) {
shardingResult.add(targetName);
}
});
}
});
return shardingResult;
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论