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

时间:2015-07-16 15:19:33

标签: cassandra cql datastax datastax-java-driver

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

我目前的代码看起来像这样:

|

但是,我想改进这一点。在这个BoundStatement的cql查询中,我希望看到这样的东西:

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(在这种情况下是两个参数)和一个分区键列表。在这种情况下,我需要做的就是绑定分区键并执行查询。不幸的是,当我将密钥绑定到此语句时,我失败并出现错误 - SELECT * FROM <column_family_name> WHERE <param1> = :p1_name AND param2 = :p2_name AND <partiotion_key_name> = ?; 。问题是,我尝试将密钥绑定到第一个参数而不是最后一个参数。这是一个字符串而不是很长。

我可以通过给分区参数一个名称来解决这个问题,但是我必须通过方法参数获取名称,或者通过指定它的索引再次需要一个额外的方法参数。无论哪种方式,如果我使用名称或索引,我必须将其与特定类型绑定。例如: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。出于某种原因,我不能将它留给BoundStatement来解释最后一个参数的类型。

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

谢谢!

1 个答案:

答案 0 :(得分:3)

我在'用于Apache Cassandra用户邮件列表的DataStax Java驱动程序'和got an answer中发布了相同的问题,说我可能会在数据传输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...
     

partitionKeys)

     

作为奖励,这也适用于复合分区键。