【问题标题】:cassandra-driver-core: pass list values to parameterized SimpleStatementcassandra-driver-core:将列表值传递给参数化的 SimpleStatement
【发布时间】:2014-09-14 21:02:20
【问题描述】:

我目前正在使用官方 Datastax 驱动程序 (V2.0) 编写一个非常基本的 CQL 访问层,并且在将参数值传递给语句时遇到了一些困难。

这是一个例子

列族(简化)

USE myKeyspace;

CREATE TABLE MyTable (
    myId timeuuid,
    myTypeId int,
    myVal varchar,
    PRIMARY_KEY( myId, myTypeId )
);

CREATE INDEX MyTable_myTypeID 
    ON MyTable( myTypeId );

基本思想是存储一些具有多个值的事件数据(每个“事件”),这就是我使用组合 PK 的原因。每个事件都有其基于时间的 UUID,每个 typeId 可能有多个条目。 从建模的角度来看,这是否有意义?

我现在要做的是仅获取具有“typeIds”选择的事件的条目。

public void myQueryCode() {

    Cluster.Builder builder = Cluster.builder();
    builder.withPort( 9142 );
    builder.addContactPoints( "127.0.0.1" );
    cluster = builder.build();
    Session session = cluster.connect( "myKeyspace" );

    List<Integer> typeFilter = new ArrayList<> ();
    typeFilter.add( 1 );
    typeFilter.add( 2 );

    Statement stmt = new SimpleStatement( 
        "SELECT * FROM MyTable where myId = ?" +
        " AND myTypeId IN (?,?)" +
        " ALLOW FILTERING",
        UUID.randomUUID(),
        typeFilter );

    ResultSet result = session.execute( stmt );

    // do something with results
}

但是,我只是在语句值的序列化中遇到了一个异常。

com.datastax.driver.core.exceptions.InvalidQueryException: Expected 4 or 0 byte int (8)
at com.datastax.driver.core.exceptions.InvalidQueryException.copy(InvalidQueryException.java:35)
at com.datastax.driver.core.DefaultResultSetFuture.extractCauseFromExecutionException(DefaultResultSetFuture.java:256)
at com.datastax.driver.core.DefaultResultSetFuture.getUninterruptibly(DefaultResultSetFuture.java:172)
at com.datastax.driver.core.AbstractSession.execute(AbstractSession.java:52)

我不确定是否将列表作为第二个参数传递,驱动程序正在使用该参数,但也许这仅适用于集合类型列上的插入?

【问题讨论】:

    标签: java cassandra cql3


    【解决方案1】:

    您是正确的,您传递的列表被强制输入第二个参数,这会导致 InvalidQueryException。

    Statement stmt = new SimpleStatement( 
            "SELECT * FROM MyTable where myId = ?#1" +
            " AND myTypeId IN (?#2,?#3)" +
            " ALLOW FILTERING",
            #1 UUID.randomUUID(),
            #2 typeFilter );
    

    由于 typeFilter 是一个列表,因此驱动程序会尝试将 List Collection 对象放入参数 2 中,但事情变得很奇怪。这是因为当您运行这样的语句(没有准备)时,驱动程序无法检查类型,Comment in code。相反,如果你传入了

    Statement stmt = new SimpleStatement( 
                "SELECT * FROM MyTable where myId = ?#1" +
                " AND myTypeId IN (?#2,?#3)" +
                " ALLOW FILTERING",
                #1 UUID.randomUUID(),
                #2 typeFilter.get(0)
                #3 typeFilter.get(1));
    

    你会没事的。或者,如果您先准备好语句,则会收到编译时错误警告。

    【讨论】:

    • 谢谢,正如我所想...当您处理不同的 typeFilter 列表长度时可能会变得很棘手,那么您必须将所有查询参数值放入 Object 数组中并传递它作为 SimpleQuery 的参数列表(原始代码适应占位符/通配符的数量)。但是,我认为我最好使用 BoundStatement,它更像是传统的 PreparedStatement,具有基于索引或别名的参数处理和特定于类型的设置器。剩下的唯一问题:我想在 PK 中有类型,但 Cassandra 2.0 不支持 PK 列上的“IN”子句。
    【解决方案2】:

    在回答您的第一个问题时,从建模的角度来看,存储“具有多个值(每个“事件”)的一些事件数据是否有意义,这就是我使用组合 PK 的原因。每个事件都有它的时间 -基于 UUID,每个 typeId 可能有多个条目,”绝对是的。这与 Cassandra 团队在其音乐服务数据建模示例中使用的场景类似:http://www.datastax.com/documentation/cql/3.1/cql/ddl/ddl_music_service_c.html

    在你的代码中寻找一个小故障,因为我可以在命令行上做你的例子:

    创建表 MyTable ( myId timeuuid, myTypeId 整数, myVal varchar, PRIMARY_KEY(myId, myTypeId) ); 创建索引 MyTable_myTypeID ON MyTable(myTypeId); 插入 mytable(myid, mytypeid, myval) 值 (d2177dd0-eaa2-11de-a572-001b779c76e3, 100, 'somechar') 插入 mytable(myid, mytypeid, myval) 值 (d2177dd0-eaa2-11de-a572-001b779c76e3, 200, 'anotherchar') SELECT * FROM MyTable where myId = d2177dd0-eaa2-11de-a572-001b779c76e3 AND myTypeId IN (100,200) 允许过滤;

    输出是:

    我的 |我的类型ID |迈瓦尔 --------------------------------------------------+----------+ ------------- d2177dd0-eaa2-11de-a572-001b779c76e3 | 100 |一些字符 d2177dd0-eaa2-11de-a572-001b779c76e3 | 200 |另一个字符

    【讨论】:

    • 是的,这是一个代码故障。 1 个 UUID 加上一个大小为 2 的列表并不意味着您要传递 3 个参数,实际上是它的 1xUUID + 1x 列表类型,导致数据类型不匹配(第二个参数是整数,没有它们的列表)。
    猜你喜欢
    • 1970-01-01
    • 2018-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多