【问题标题】:Cassandra delete/update a row and get its previous valueCassandra 删除/更新一行并获取其先前的值
【发布时间】:2019-09-16 16:22:14
【问题描述】:

如何从 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]...)

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

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_userliked_items_by_user、...表。这发生在执行SELECT 语句之后,并且在DELETE 查询之前执行UPDATE 查询。
  • deleteItem 方法根据刚刚通过 SELECT 语句检索到的数据从 owned_items_by_userliked_items_by_user、... 表中删除项目。该数据尚不包含刚刚添加的like。该项目因此被删除,但刚刚添加的点赞仍保留在 liked_items_by_user 表中。

【问题讨论】:

    标签: cassandra cql


    【解决方案1】:

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

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

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

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

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

    TLDR:

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

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

    【讨论】:

    • 我附上了我的问题出现在问题中的示例场景。您知道解决方法如何解决这种情况吗?我虽然关于物化视图,但我不知道如何为set&lt;text&gt; 创建物化视图。
    • @Aki 然后批量删除交叉表,这样就可以从2个表中删除了。
    【解决方案2】:

    您可以事先进行选择,然后在删除时执行轻量级事务,以确保数据看起来仍然与您选择时完全一样。如果是这样,您就知道删除前的最新状态。如果没有,请继续重试整个过程,直到成功为止。

    【讨论】:

    • 感谢您的回复,这就是我的最终结果。我只是有点担心这可能不是很好。
    猜你喜欢
    • 2022-01-01
    • 2020-05-25
    • 1970-01-01
    • 2017-12-18
    • 2019-11-10
    • 1970-01-01
    • 1970-01-01
    • 2016-08-05
    • 1970-01-01
    相关资源
    最近更新 更多