具有多个参数和多分区查询的 Cassandra BoundStatement

标签 cassandra cql datastax datastax-java-driver

在阅读 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> = ?;

我希望此方法的客户端给我一个带有已绑定(bind)参数(在本例中为两个参数)和分区键列表的 BoundStatement。在这种情况下,我需要做的就是绑定(bind)分区键并执行查询。不幸的是,当我将 key 绑定(bind)到此语句时,我失败并出现错误 - 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 .问题是,我尝试将 key 绑定(bind)到第一个参数而不是最后一个。这是一个字符串,不是很长。

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

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

谢谢!

最佳答案

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

In JAVA-721 (to be introduced in 2.2) we are tentatively planning on adding the following methods with the signature to 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);
 }

To avoid passing the parameter name, one thing you could do is look for a position that isn't bound yet:

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");
}

I don't recommend it though, because it's ugly and unpredictable if the user forgot to bind one of the non-PK variables.

The way I would do it is require the user to pass a callback that sets the PK:

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

partitionKeys)

As a bonus, this will also work with composite partition keys.

关于具有多个参数和多分区查询的 Cassandra BoundStatement,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31458283/

相关文章:

apache-spark - Cassandra:身份验证错误......在集群配置中找不到身份验证器

csv - 无法将 '2012/11/11' 强制转换为格式化日期(长)

cassandra - 如何更改 CQL 版本?

Cassandra - 写入不会失败,但不会插入值

python - Datastax Cassandra 上的 CCM - Python 2.6 错误和创建本地集群失败

java - Cassandra Java 连接错误

cassandra - 如何在Cassandra中实现触发器?

cassandra - 有没有一种方法可以有效地获取 Cassandra 中簇键上的前 n 个最小数据点?

cassandra - 在 Cassandra 2.2 中,无法创建包含密码的角色

cassandra - 在 CQL 中使用元组操作对分区行进行切片