在阅读 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/