首页 文章

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

提问于
浏览
3

在阅读了datastax博客中的“Asynchronous queries with the Java driver”文章之后,我试图实现类似于名为'Case study: multi-partition query, a.k.a. “client-side SELECT...IN“'的部分中的解决方案 .

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

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("<key_name>", partitionKey); . 出于某种原因,我不能将它留给BoundStatement来解释最后一个参数的类型 .

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

谢谢!

1 回答

  • 3

    我've posted the same question in '用于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))
    回归我;
    抛出新的IllegalArgumentException(“找不到未设置的位置”);
    }
    我不推荐它,因为如果用户忘记绑定其中一个非PK变量,它会很难看并且不可预测 . 我这样做的方法是要求用户传递一个回调来设置PK:interface PKBinder <T> {
    void bind(BoundStatement bs,T pk);
    }
    public <T> Future <List <ResultSet >> executeMultipleAsync(最终BoundStatement语句,PKBinder <T> pkBinder,final T ...
    partitionKeys)作为奖励,这也适用于复合分区键 .

相关问题