如何从Cassandra中删除一行并获取删除之前的值?
我可以串行执行SELECT
和DELETE
查询,但是如何确保在执行这两个查询之间不会同时更改数据?
我试图批量执行SELECT
和DELETE
查询,但这似乎是不允许的。
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]...)
在我的用例中,我有一个主表来存储项目的数据。我已经构建了几个表,允许根据这些信息查找项目。如果我从主表中删除一个项目,我还必须从其他表中删除它。
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));
...
如果我删除某个项目并且同时有人例如,我担心这些表格可能包含错误的数据。点击同一项目的喜欢按钮。
deleteItem
方法执行SELECT
查询以从主表中获取项目的当前行likeItem
方法运行UPDATE
查询并将项目插入owned_items_by_user
,liked_items_by_user
,...表格。这是在执行SELECT
语句并在UPDATE
查询之前执行DELETE
查询之后发生的。deleteItem
方法根据刚刚通过owned_items_by_user
语句检索的数据从liked_items_by_user
,SELECT
,...表中删除项目。此数据尚未包含刚才添加的内容。因此删除了该项目,但刚刚添加的项目保留在liked_items_by_user
表中。您可以事先进行选择,然后对删除执行轻量级事务,以确保数据看起来仍然与您选择时完全一样。如果是,则在删除之前知道最新状态。如果没有,请继续重试整个过程,直到它坚持下去。
不幸的是,您无法在批处理语句中执行SELECT
查询。如果您阅读文档here,则只能使用insert,update和delete语句。
您正在寻找的是执行的原子性,但批处理语句不会成为前进的方向。如果数据已被更改,则最糟糕的情况是僵尸或可能重新出现的数据。
Cassandra使用等级期机制来处理这个问题,你可以找到详细信息here。如果由于某种原因,这对您的业务逻辑至关重要,那么在这种情况下您可以做的“最好”的事情是提高一致性级别,或者在应用程序级别重构读取模式,而不是依赖于完美的原子性,无论哪个正确的交易关闭是给你的。所以你要么放弃一些表现,要么调低要求。
在实践中,QUORUM
应该足以满足大多数情况下的大多数情况。或者,您可以执行ALL
,并且您支付性能损失,但这意味着给定foo
分区键的所有副本将必须在commitlog
和memtable
中确认写入。注意,这仍然意味着在删除是flush
之前需要发生来自commitlog的complete
,但是您可以将一致性调整到所需的级别。
你没有SQL意义上的原子性,但根据吞吐量,你不太可能需要它(触摸木材)。
TLDR:
USE CONSISTENCY ALL;
DELETE FROM data_by_user WHERE user = 'foo';
这应该够了吧。你现在看到的错误基本上是CQL 3的ANTLR3语法解析器,它不是为了接受批量内部的SELECT查询而仅仅因为它们不受支持,你可以看到here。