Cassandra delete/update 一行并获取其之前的值

Cassandra delete/update a row and get its previous value

如何从 Cassandra 中删除一行并获取它在删除之前的值?

我可以连续执行 SELECTDELETE 查询,但我如何确定数据在这两个查询的执行期间没有同时更改?

我试过批量执行 SELECTDELETE 查询,但这似乎是不允许的。

cqlsh:foo> BEGIN BATCH
       ...     SELECT * FROM data_by_user WHERE user = 'foo';
       ...     DELETE FROM data_by_user WHERE user = 'foo';
       ... APPLY BATCH;
SyntaxException: line 2:4 mismatched input 'SELECT' expecting K_APPLY (BEGIN BATCH    [SELECT]...)

在我的用例中,我有一个主要 table 用于存储项目数据。我已经构建了几个 table 允许根据这些信息查找项目。 如果我从主 table 中删除一个项目,我还必须从其他 table 中删除它。

CREATE TABLE items (id text PRIMARY KEY, owner text, liking_users set<text>, ...);

CREATE TABLE owned_items_by_user (user text, item_id text, PRIMARY KEY ((user), item_id));
CREATE TABLE liked_items_by_user (user text, item_id tect, PRIMARY KEY ((user), item_id));
...

我担心 tables 可能包含错误的数据,如果我删除了一个项目,同时删除了某人,例如点击相同项目的“赞”按钮。

遗憾的是,您不能在批处理语句中执行 SELECT 查询。如果您阅读了文档 here,则只能使用插入、更新和删除语句。

您正在寻找的是执行的原子性,但批处理语句不会成为前进的方向。如果数据已被更改,最坏的情况是僵尸或可能重新出现的数据。

Cassandra使用了一个等级周期机制来处理这个,你可以找到细节here。如果出于某种原因,这对您的业务逻辑至关重要,那么在这种情况下,您可以做的 "best" 事情是提高一致性级别,或者在应用程序级别重构读取模式以不依赖于完美的原子性,无论哪个正确的权衡是给你的。所以要么你放弃一些性能,要么调低要求。

实际上,QUORUM应该足以满足大部分时间的大多数情况。或者,您可以执行 ALL,并支付性能损失,但这意味着给定 foo 分区键的所有副本都必须确认 commitlogmemtable。请注意,这仍然意味着提交日志中的 flush 需要在删除 complete 之前发生,但您可以将一致性调整到您需要的级别。

您没有 SQL 意义上的原子性,但根据吞吐量,您不太可能需要它(碰木头)。

TLDR:

USE CONSISTENCY ALL;
DELETE FROM data_by_user WHERE user = 'foo';

这应该可以解决问题。您现在看到的错误基本上是 CQL 3 的 ANTLR3 语法解析器,它不是为了接受 SELECT 批次内的查询而设计的,因为它们不受支持,您可以看到 here.

您可以预先执行 select,然后在删除时执行轻量级事务,以确保数据看起来仍然与您 select 编辑时完全一样。如果是,则您知道删除前的最新状态。如果没有,请继续重试整个过程,直到坚持下去。