sharding-jdbc行分片策略默认不支持按分片键的范围查询

2023-10-31

sharding-jdbc行分片策略默认不支持按分片键的范围查询

在开发时,对主键id做了 范围查询。结果遇到如下报错:

Caused by: org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IllegalStateException: Inline strategy cannot support this type sharding:RangeRouteValue(columnName=id, tableName=table, valueRange=(12))
### The error may exist in file [E:\work\Project\target\classes\mapper\XXXMapper.xml] 
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT id     FROM table     where id > 1 and id < 2  
### Cause: java.lang.IllegalStateException: Inline strategy cannot support this type sharding:RangeRouteValue(columnName=id, tableName=table, valueRange=(12))
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:149)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:426)
	... 74 more
Caused by: java.lang.IllegalStateException: Inline strategy cannot support this type sharding:RangeRouteValue(columnName=id, tableName=table, valueRange=(12))
	at com.google.common.base.Preconditions.checkState(Preconditions.java:173)
	at org.apache.shardingsphere.core.strategy.route.inline.InlineShardingStrategy.doSharding(InlineShardingStrategy.java:62)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.routeTables(ShardingStandardRoutingEngine.java:214)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.route0(ShardingStandardRoutingEngine.java:195)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.routeByShardingConditionsWithCondition(ShardingStandardRoutingEngine.java:121)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.routeByShardingConditions(ShardingStandardRoutingEngine.java:115)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.getDataNodes(ShardingStandardRoutingEngine.java:96)
	at org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine.route(ShardingStandardRoutingEngine.java:74)
	at org.apache.shardingsphere.sharding.route.engine.ShardingRouteDecorator.decorate(ShardingRouteDecorator.java:69)
	at org.apache.shardingsphere.sharding.route.engine.ShardingRouteDecorator.decorate(ShardingRouteDecorator.java:53)
	at org.apache.shardingsphere.underlying.route.DataNodeRouter.executeRoute(DataNodeRouter.java:91)
	at org.apache.shardingsphere.underlying.route.DataNodeRouter.route(DataNodeRouter.java:76)
	at org.apache.shardingsphere.underlying.pluggble.prepare.PreparedQueryPrepareEngine.route(PreparedQueryPrepareEngine.java:54)
	at org.apache.shardingsphere.underlying.pluggble.prepare.BasePrepareEngine.executeRoute(BasePrepareEngine.java:96)
	at org.apache.shardingsphere.underlying.pluggble.prepare.BasePrepareEngine.prepare(BasePrepareEngine.java:83)
	at org.apache.shardingsphere.shardingjdbc.jdbc.core.statement.ShardingPreparedStatement.prepare(ShardingPreparedStatement.java:183)
	at org.apache.shardingsphere.shardingjdbc.jdbc.core.statement.ShardingPreparedStatement.execute(ShardingPreparedStatement.java:143)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:59)
	at com.sun.proxy.$Proxy292.execute(Unknown Source)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:64)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325)
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)
	at com.github.pagehelper.PageInterceptor.intercept(PageInterceptor.java:111)
	at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
	at com.sun.proxy.$Proxy291.query(Unknown Source)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
	... 80 more

原因:使用行分片策略

原先的sharding-jdbc的分片策略配置是:

sharding:
      binding-tables: tableName
      tables:
        tableName:
          actual-data-nodes: ds0.tableName_$->{0..1}
          table-strategy:
            inline:
              sharding-column: id
              algorithm-expression: tableName_$->{id % 2}

查阅官方资料、github发现:
在这里插入图片描述

上面的配置,使用了主键id作为单分片键,行表达式的分片策略。该分片策略只支持 = 和 in 操作符,并不支持范围查询。如果你想要使用范围查询,你需要配置 开启标准策略。

解决方案:使用标准分片策略

对应配置:

sharding:
  binding-tables: tableName
  tables:
    tableName:
      table-strategy:
        standard:#用于单分片键的标准分片场景
          sharding-column: id  #分片列名称
          precise-algorithm-class-name: com.project.com.PreciseModuloAlgorithm
          #精确分片算法类名称,用于=和IN。。该类需实现PreciseShardingAlgorithm接口并提供无参数的构造器
          range-algorithm-class-name: com.project.com.component.RangeModuloAlgorithm
          #范围分片算法类名称,用于BETWEEN,可选。该类需实现RangeShardingAlgorithm接口并提供无参数的构造器

问题具体可参考,官方github上的issues提问:https://github.com/apache/shardingsphere/issues/4180
其他配置可参考:https://shardingsphere.apache.org/document/legacy/4.x/document/cn/manual/sharding-jdbc/configuration/config-yaml/
对于具体的分片算法类,可参考官方github上的example:https://github.com/apache/shardingsphere-example
分片算法类 需要自己根据实际场景进行开发,这里贴出官方example里的实现类:

public final class PreciseModuloAlgorithm implements PreciseShardingAlgorithm<Integer> {

    @Override
    public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<Integer> shardingValue) {
        for (String each : availableTargetNames) {
            if (each.endsWith(shardingValue.getValue() % 10 + "")) {
                return each;
            }
        }
        throw new UnsupportedOperationException();
    }
}

public final class RangeModuloAlgorithm implements RangeShardingAlgorithm<Integer> {
    
    @Override
    public Collection<String> doSharding(final Collection<String> availableTargetNames, final RangeShardingValue<Integer> shardingValue) {
        Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());
        int minValue = shardingValue.getValueRange().hasLowerBound() ? shardingValue.getValueRange().lowerEndpoint() : Integer.MIN_VALUE;
        int maxValue = shardingValue.getValueRange().hasUpperBound() ? shardingValue.getValueRange().upperEndpoint() : Integer.MAX_VALUE;
        // 最大值减最小值,得到差
        long range = BigInteger.valueOf(maxValue).subtract(BigInteger.valueOf(minValue)).longValue();
        // 最小值得绝对值除10的余数
        int begin = Math.abs(minValue) % 10;
        // 超过9直接返回可用的表名,这里的9是,自己的分片策略值
        // 假设我的分片策略是:对id除以10,取余数
        if (range > 9) {
            return availableTargetNames;
        }
        // 如果差在分片策略内的,就直接取余数,得到对应的表名
        for (int i = begin; i <= range; i += 1) {
            for (String each : availableTargetNames) {
                if (each.endsWith(i + "")) {
                    result.add(each);
                }
            }
        }
        return result;
    }
}

sharding-jdbc 分片策略

分片策略
包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。目前提供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。不分片的策略。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

sharding-jdbc行分片策略默认不支持按分片键的范围查询 的相关文章

  • 如何使用 SimpleDateFormat 解析多种格式的日期

    我正在尝试解析文档中的一些日期 用户似乎以类似但不完全相同的格式输入了这些日期 以下是格式 9 09 9 2009 09 2009 9 1 2009 9 1 2009 尝试解析所有这些内容的最佳方法是什么 这些似乎是最常见的 但我想让我困扰
  • 部署示例 Spring Web MVC 项目

    我是 Tomcat Maven 和 Spring Web MVC 准确地说是框架 v3 的新手 我试图建立example https anonsvn springframework org svn spring samples 项目mvc
  • 为什么 java 编译器不报告 Intellij 中多播表达式的未经检查的强制转换警告?

    为什么下面的代码没有报告 Intellij IDEA 的未经检查的警告jdk 1 8 0 121自从Supplier
  • 使用 RecyclerView 适配器在运行时更改布局屏幕

    我有两个布局文件 如下所示 如果列表中存在数据 则我显示此布局 当列表为空时 我会显示此布局 现在我想在运行时更改布局 当用户从列表中删除最后一项时 我想将布局更改为第二张图片中显示的 空购物车布局 In getItemCount Recy
  • 内存一致性 - Java 中的happens-before关系[重复]

    这个问题在这里已经有答案了 在阅读有关内存一致性错误的 Java 文档时 我发现与创建 发生 之前 关系的两个操作相关的点 当语句调用时Thread start 每个具有 与该语句发生之前的关系也有一个 与 new 执行的每个语句之间发生的
  • 将表值参数与 SQL Server JDBC 结合使用

    任何人都可以提供一些有关如何将表值参数 TVP 与 SQL Server JDBC 一起使用的指导吗 我使用的是微软提供的6 0版本的SQL Server驱动程序 我已经查看了官方文档 https msdn microsoft com en
  • RSA OAEP、Golang 加密、Java 解密 -BadPaddingException:解密错误

    我正在尝试解密使用 RSA OAEP 在 Golang 中加密的字符串 但出现 BadPaddingException 解密错误 很难弄清楚我错过了什么 这是Golang加密方法 func encryptString rootPEM io
  • 获取给定类文件的目录路径

    我遇到的代码尝试从类本身的 class 文件所在的同一目录中读取一些配置文件 File configFiles new File this getClass getResource getPath listFiles new Filenam
  • 如何将使用消息侦听器接收到的 JMS 消息转换为域对象

    我在用 春季3 1 1 ActiveMQ 5 6 0 我有两个 JMS 应用程序 应用程序 A 使用 JmsTemplate 使用 jmsTemplate convertAndSend msg 发送域对象 App B 使用消息监听器并注册了
  • 如何记录来自 Akka (Java) 的所有传入消息

    在 Scala 中 您可以使用 LoggingReceive 包装接收函数 如何通过 Java API 实现相同的目标 def receive LoggingReceive case x do something Scala API 有Lo
  • Android Studio 将音乐文件读取为文本文件,如何恢复它?

    gameAlert mp3是我的声音文件 运行应用程序时 它询问我该文件不与任何文件类型关联 请定义关联 我选择TextFile错误地 现在我的音乐文件被读取为文本文件 我如何将其转换回music file protected void o
  • Espresso 和 Proguard 的 Java.lang.NoClassDefFoundError

    我对 Espresso 不太有经验 但我终于成功地运行了它 我有一个应用程序需要通过 Proguard 缩小才能处于 56K 方法之下 该应用程序以 3 秒的动画开始 因此我需要等到该动画结束才能继续 这就是我尝试用该方法做的事情waitF
  • 解析输入,除了 System.in.read() 之外不使用任何东西

    我很难找到具体的细节System in read 有效 也许有人可以帮助我 似乎扫描仪会更好 但我不允许使用它 我被分配了一个任务 我应该以 Boolean Operator Boolean 的形式读取控制台用户输入 例如T F 或 T T
  • 如何通过 Inno Setup for NetBeans 使用自定义 .iss 文件

    我将 Inno Setup 5 与 NetBeans 8 一起使用 并且我已经能够创建一个安装程序来安装该应用程序C users username local appname 但是我希望将其安装在C Programfiles 我如何在 Ne
  • JVM:是否可以操作帧堆栈?

    假设我需要执行N同一线程中的任务 这些任务有时可能需要来自外部存储的一些值 我事先不知道哪个任务可能需要这样的值以及何时 获取速度要快得多M价值观是一次性的而不是相同的M值在M查询外部存储 注意我不能指望任务本身进行合作 它们只不过是 ja
  • 挂钩 Eclipse 构建过程吗?

    我希望在 Eclipse 中按下构建按钮时能够运行一个简单的 Java 程序 目前 当我单击 构建 时 它会运行一些 JRebel 日志记录代码 我有一个程序可以解析 JRebel 日志文件并将统计信息存储在数据库中 是否可以编写一个插件或
  • Android AutoCompleteTextView 带芯片

    我不确定我是否使用了正确的词语来描述此 UI 功能 但我已附上我希望在我的应用程序中实现的目标的快照 它由 Go SMS 使用 用户在编辑文本中键入联系人 在用户从完成下拉列表中选择联系人后 该联系人将被插入到编辑文本中 如附图所示 编辑文
  • Java &= 运算符应用 & 或 && 吗?

    Assuming boolean a false 我想知道是否这样做 a b 相当于 a a b logical AND a is false hence b is not evaluated 或者另一方面 这意味着 a a b Bitwi
  • 嵌入式 Jetty - 以编程方式添加基于表单的身份验证

    有没有一种方法可以按如下方式以编程方式添加基于表单的身份验证 我用的是我自己的LdapLoginModule 最初我使用基本身份验证并且工作正常 但现在我想在登录页面上进行更多控制 例如显示徽标等 有没有好的样品 我正在使用嵌入式 jett
  • JAXB - 列表<可序列化>?

    我使用 xjc 制作了一些课程 public class MyType XmlElementRefs XmlElementRef name MyInnerType type JAXBElement class required false

随机推荐