有没有人有使用preparedStatement()的CQL UPDATE的工作语法,他们可以与我分享?

时间:2015-04-25 03:00:33

标签: cassandra cql datastax-java-driver

当我执行INSERT时,事情进展顺利:

String insertText = "UPDATE alpha_screen SET screen = screen + ['newword'] WHERE alpha = 'keyvalue' VALUES (?, ?)";
PreparedStatement preparedStatement = InsertWordCount.PrepareText(insertText);
BoundStatement boundStatement = preparedStatement.bind(newword, keyvalue);  // UPDATE positions
getSession().execute(boundStatement); 

com.datastax.driver.core.exceptions.SyntaxError: line 1:79 missing EOF at 'VALUES' (...] WHERE alpha = 'keyvalue' [VALUES] (...)
at com.datastax.driver.core.exceptions.SyntaxError.copy(SyntaxError.java:35)
at com.datastax.driver.core.DefaultResultSetFuture.extractCauseFromExecutionException(DefaultResultSetFuture.java:289)
at com.datastax.driver.core.AbstractSession.prepare(AbstractSession.java:79)
at playlist.model.InsertWordCount.PrepareText(InsertWordCount.java:13)
at playlist.model.CountDAO.screenWord(CountDAO.java:99)

与PrepareText UPDATE不一样:

UPDATE users
  SET top_places = top_places + [ 'mordor' ] WHERE user_id = 'frodo';

看起来它应该适用于文档中的这个示例:

通过在UPDATE命令中切换新元素数据和列表名称的顺序,将元素附加到列表中。

String insertText = "UPDATE alpha_screen SET screen = screen + ['twoword'] WHERE alpha = 'keyvalue' ";
PreparedStatement preparedStatement = InsertWordCount.PrepareText(insertText);
BoundStatement boundStatement = preparedStatement.bind();  // No VALUES
getSession().execute(boundStatement); 

cqlsh> SELECT * FROM rant.alpha_screen;

alpha     | screen
----------+-----------------------------------
a         |                        ['aboard']
c         |                      ['checking']
p         |                          ['pull']
keyvalue  | ['newword', 'oneword', 'twoword']
r         |                       ['rotting']
t         |                          ['time']

事实上,没有VALUES,它可以正常工作:

<div class="menuBar">

4 个答案:

答案 0 :(得分:3)

我不确定您正在查看哪些文档(下次请提供链接)。此外,它有助于指出您正在使用的语言,以及哪个驱动程序和版本。通过阅读您的错误消息,我能够确定您正在使用DataStax Java驱动程序,但我仍然不确定您使用的是哪个版本(我假设2.1)。在任何情况下,VALUES都不是UPDATE语句的有效子句。

此示例显示了一个使用DataStax Java 2.1驱动程序通过预准备语句插入List的方法:

private static void insertAlphaScreen(Session _session, String _alpha, List<String> _screen)
{
    PreparedStatement statement = _session.prepare("UPDATE stackoverflow2.alpha_screen " +
        "SET screen=? WHERE alpha=?");

    BoundStatement boundStatement = statement.bind(_screen,_alpha);
    _session.execute(boundStatement);
}

当我准备一个列表并从我的main方法调用它时:

    List<String> screen = new ArrayList<String>();
    screen.add("aboard");
    insertAlphaScreen(session, "a", screen);

这是我的CQL表中的结果:

 alpha    | screen
----------+-------------
        a |  ['aboard']

不幸的是,如果我只是想在现有的List集合中添加一个元素,那么确实没有好办法。有两种方法可以实现这一目标:

  1. 首先阅读该集合,然后通过准备好的声明编写整个集合。当然,这意味着您必须读入集合,添加值,然后将其写回Cassandra(可能使用上述方法)。
  2. 另一个选项是通过一起解析字符串来创建更新语句。这当然不能保护您免受SQL(CQL)注入攻击。
  3. 对于第二个选项,该方法与您在上面构建CQL UPDATE语句的方式类似:

    private static void updateAlphaScreen(Session _session, String _alpha, String _screen)
    {
        PreparedStatement statement = _session.prepare("UPDATE stackoverflow2.alpha_screen " +
            "SET screen=screen+['" + _screen + "'] WHERE alpha=?");
    
        BoundStatement boundStatement = statement.bind(_alpha);
        _session.execute(boundStatement);
    }
    

答案 1 :(得分:1)

感谢您抽出宝贵时间回答这个问题。是的,VALUES仅与INSERT一起使用,从不与UPDATE一起使用。

我提出了你的第二个建议,但测试显示我无法使用prepare / bind。

此外,SQL注入问题真是令人大开眼界。真是太棒了!

此代码正是我所需要的:

String source = "UPDATE alpha_screen SET screen = screen + ['newWord'] WHERE alpha = 'keyvalue'";
String update = source.substring(0,42) + newWord + source.substring(53,69) +  keyvalue + source.substring(77,78) + ";";
getSession().execute(update);

为了完整性,我正在运行Cassandra-2.1.2 DataStax Java Driver 2.1。

CQLSH显示[cqlsh 5.0.1 | Cassandra 2.1.2 | CQL spec 3.2.0 | Native protocol v3]

Cassandra 2.x的CQL http://docs.datastax.com/en/cql/3.1/cql/cql_using/use_list_t.html

准备声明:https://cassandra.apache.org/doc/cql3/CQL.html#preparedStatement

答案 2 :(得分:1)

以下是准备好的更新语句的java示例,Datastax java driver 3,Cassandra 3.6

这是我的代码中的复制粘贴,变量名称已更改。如果有拼写错误,请告诉我。我找不到一个不需要按摩字符串的示例,甚至在任何Datastax文档中都没有。 :(

声明:

private PreparedStatement statement_update;

在应用程序启动时的启动方法中(您必须先连接到群集并打开会话,可能采用相同的启动方法):

Clause filter1= QueryBuilder.eq("column1", QueryBuilder.bindMarker("column1"));
Assignment assignment1 = QueryBuilder.set("column2",QueryBuilder.bindMarker("column2"));
Assignment assignment2 = QueryBuilder.set("column3",QueryBuilder.bindMarker("column3"));

Update update1 = (Update) QueryBuilder.update("keyspace1", "table1")
//                  .where(filter1) // does not work here
//                  .with(assignment1).and(assignment2)  // does not work here
                    .setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM)
                    ;
update1.where(filter1).ifExists();
update1.with(assignment1).and(assignment2);

statement_update = session.prepare(update1); 

稍后在一个方法中:

BoundStatement statement = new BoundStatement(this.statement_update);
statement.setString("column1", "some value for filter");
statement.setString("column2", "some value to set/update");
statement.setString("column3", "some other value to set/update");

ResultSet rs = session.execute(statement);

答案 3 :(得分:0)

这是您要查找的工作代码:

String strCQL = "update EMPLOYRK set Employee_Name=?, Employee_Title=?, Employee_Phone=?, Business_Address=?, Branch_ID=?, Department_ID=? where Employee_ID=?";
PreparedStatement preparedStatement = session.prepare(strCQL);
BoundStatement boundStatement = new  BoundStatement(preparedStatement);
boundStatement.bind(Employee_Name,Employee_Title,Employee_Phone,Business_Address,Branch_ID,Department_ID,Employee_ID);
session.execute(boundStatement);

EMPLOYRK是我的表格名称。我正在尝试在此处更新表的6列。

PS:我使用了Eclipse的datastax驱动程序来运行该程序。