无法使用Java删除以前在Cassandra中使用upsert创建的行

Car*_*tti 4 java cassandra datastax-java-driver

TL; DR是我无法使用Java删除先前使用upsert创建的行.

基本上我有这样一个表:

CREATE TABLE transactions (
key text PRIMARY KEY,
created_at timestamp
);
Run Code Online (Sandbox Code Playgroud)

然后我执行:

String sql = "update transactions set created_at = toTimestamp(now()) where key = 'test' if created_at = null"; 
session.execute(sql)
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,行被创建:

cqlsh:thingleme> SELECT * FROM  transactions ;

 key  | created_at
------+---------------------------------
 test | 2018-01-30 16:35:16.663000+0000
Run Code Online (Sandbox Code Playgroud)

但是(这是让我发疯的原因)如果我执行:

sql = "delete from transactions where key = 'test'"; 
ResultSet resultSet = session.execute(sql);
Run Code Online (Sandbox Code Playgroud)

什么都没发生.我的意思是:没有抛出异常而且行仍在那里!

其他一些奇怪的东西:

  • 如果我用普通插入替换upsert,那么删除工作
  • 如果我使用cqlsh直接运行sql代码(更新和删除),它的工作原理
  • 如果我针对EmbeddedCassandraService运行此代码,它可以工作(这非常糟糕,因为我的集成测试只是绿色!)

我的环境:

  • cassandra:3.11.1
  • datastax java驱动程序:3.4.0
  • docker image:cassandra:3.11.1

关于如何解决这个问题的任何想法/建议真的很感激;-)

And*_*ert 6

我认为您遇到的问题可能是通过轻量级事务(LWT)(update transactions set created_at = toTimestamp(now()) where key = 'test' if created_at = null)和非LWT(delete from transactions where key = 'test')的混合来解释的.

Cassandra使用时间戳来确定哪些突变(删除,更新)是最近应用的.使用LWT时,时间戳分配与不使用LWT时不同:

轻量级事务将阻止发生其他轻量级事务,但不会阻止正常的读写操作发生.轻量级事务使用与正常操作不同的时间戳机制,并且混合LWT和正常操作可能导致错误.如果使用轻量级事务来写入分区中的行,则只应使用读取和写入操作的轻量级事务.

来源:如何使用线性化一致性完成轻量级事务?

更复杂的是,默认情况下,java驱动程序使用客户端时间戳,这意味着写时间戳由客户端而不是协调的cassandra节点确定.但是,使用LWT时,会绕过客户端时间戳.在您的情况下,除非您禁用客户端时间戳,否则您的非LWT查询正在使用客户端时间戳,其中您的LWT查询使用cassandra中的paxos逻辑分配的时间戳.在任何情况下,即使驱动程序没有分配客户端时间戳,这仍然可能是一个问题,因为对于LWT和非LWT,时间戳分配逻辑在C*端也是不同的.

要解决此问题,您可以将delete语句更改为包含IF EXISTS,即:

delete from transactions where key = 'test' if exists

来自java驱动程序邮件列表的类似问题

  • 嘿安迪,它工作!!! 你做了我的一天......非常感谢!:-)顺便说一下,我很难找出问题因为嵌入式cassandra没有显示出这种行为...... (2认同)