【问题标题】:Cassandra BoundStatement with Multiple Parameters and Multi-Partition Query具有多个参数和多分区查询的 Cassandra BoundStatement
【发布时间】:2015-10-06 03:20:51
【问题描述】:

在阅读了 datastax 博客中的“Asynchronous queries with the Java driver”文章后,我试图实现一个类似于“案例研究:多分区查询”一节中的解决方案,也就是“客户端 SELECT...在“”。

我目前的代码如下所示:

public Future<List<ResultSet>> executeMultipleAsync(final BoundStatement statement, final Object... partitionKeys) {
    List<Future<ResultSet>> futures = Lists.newArrayListWithExpectedSize(partitionKeys.length);
    for (Object partitionKey : partitionKeys) {
      Statement bs = statement.bind(partitionKey);
      futures.add(executeWithRetry(bs));
    }
    return Futures.successfulAsList(futures);
}

但是,我想对此进行改进。在这个 BoundStatement 持有的 cql 查询中,我想要一些看起来像这样的东西:

SELECT * FROM <column_family_name> WHERE <param1> = :p1_name AND param2 = :p2_name AND <partiotion_key_name> = ?;

我希望此方法的客户端给我一个 BoundStatement,其中包含已绑定的参数(在本例中为两个参数)和分区键列表。在这种情况下,我需要做的就是绑定分区键并执行查询。不幸的是,当我将密钥绑定到此语句时,我失败并出现错误 - com.datastax.driver.core.exceptions.InvalidTypeException: Invalid type for value 0 of CQL type varchar, expecting class java.lang.String but class java.lang.Long provided。问题是,我尝试将密钥绑定到第一个参数而不是最后一个参数。这是一个字符串而不是一个长的。

我可以通过给分区参数一个名称来解决这个问题,但是我必须通过方法参数获取名称,或者通过指定它的索引,这又需要一个额外的方法参数。无论哪种方式,如果我使用名称或索引,我必须将它与特定类型绑定。例如:bs.setLong("&lt;key_name&gt;", partitionKey);。由于某种原因,我不能让 BoundStatement 来解释最后一个参数的类型。

我想避免显式传递参数名称并绕过类型问题。有什么可以做的吗?

谢谢!

【问题讨论】:

    标签: cassandra cql datastax datastax-java-driver


    【解决方案1】:

    我在“用于 Apache Cassandra 用户邮件列表的 DataStax Java 驱动程序”和got an answer 中发布了相同的问题,说我缺少的功能可能会添加到 datastax Java 驱动程序的下一个版本 (2.2) 中。

    在 JAVA-721(将在 2.2 中引入)中,我们暂定计划 将以下带有签名的方法添加到BoundStatement:

    public BoundStatement setObject(int i, V v) public BoundStatement setObject(String name, V v)

    您可以在 2.1 中模拟 setObject:

    void setObject(BoundStatement bs, int position, Object object,
                   ProtocolVersion protocolVersion) {
         DataType type =  bs.preparedStatement().getVariables().getType(position);
         ByteBuffer buffer = type.serialize(object, protocolVersion);
         bs.setBytesUnsafe(position, buffer);
     }
    

    为避免传递参数名称,您可以做的一件事是查看 对于尚未绑定的位置:

    int findUnsetPosition(BoundStatement bs) {
        int size = bs.preparedStatement().getVariables().size();
        for (int i = 0; i < size; i++)
            if (!bs.isSet(i))
                return i;
        throw new IllegalArgumentException("found no unset position");
    }
    

    不过我不推荐它,因为如果 用户忘记绑定非 PK 变量之一。

    我会这样做的方式是要求用户传递一个回调设置 PK:

    interface PKBinder<T> {
        void bind(BoundStatement bs, T pk);
    }
    public <T> Future<List<ResultSet>> executeMultipleAsync(final BoundStatement statement, PKBinder<T> pkBinder, final T...
    

    分区键)

    另外,这也适用于复合分区键。

    【讨论】:

      猜你喜欢
      • 2019-05-11
      • 1970-01-01
      • 1970-01-01
      • 2019-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-03
      • 2011-02-09
      相关资源
      最近更新 更多