Cassandra delete/update 一行并获取其之前的值
Cassandra delete/update a row and get its previous value
如何从 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]...)
在我的用例中,我有一个主要 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 可能包含错误的数据,如果我删除了一个项目,同时删除了某人,例如点击相同项目的“赞”按钮。
deleteItem
方法执行 SELECT
查询以从主 table 中获取项目的当前行
- 同时执行的
likeItem
方法运行 UPDATE
查询并将项目插入 owned_items_by_user
、liked_items_by_user
、... table秒。这发生在 SELECT
语句执行之后,UPDATE
查询在 DELETE
查询之前执行。
deleteItem
方法根据刚刚通过 SELECT
陈述。该数据还不包含刚刚添加的点赞。 item因此被删除,但是刚添加的like还在liked_items_by_user
table.
遗憾的是,您不能在批处理语句中执行 SELECT
查询。如果您阅读了文档 here,则只能使用插入、更新和删除语句。
您正在寻找的是执行的原子性,但批处理语句不会成为前进的方向。如果数据已被更改,最坏的情况是僵尸或可能重新出现的数据。
Cassandra使用了一个等级周期机制来处理这个,你可以找到细节here。如果出于某种原因,这对您的业务逻辑至关重要,那么在这种情况下,您可以做的 "best" 事情是提高一致性级别,或者在应用程序级别重构读取模式以不依赖于完美的原子性,无论哪个正确的权衡是给你的。所以要么你放弃一些性能,要么调低要求。
实际上,QUORUM
应该足以满足大部分时间的大多数情况。或者,您可以执行 ALL
,并支付性能损失,但这意味着给定 foo
分区键的所有副本都必须确认 commitlog
和memtable
。请注意,这仍然意味着提交日志中的 flush
需要在删除 complete
之前发生,但您可以将一致性调整到您需要的级别。
您没有 SQL 意义上的原子性,但根据吞吐量,您不太可能需要它(碰木头)。
TLDR:
USE CONSISTENCY ALL;
DELETE FROM data_by_user WHERE user = 'foo';
这应该可以解决问题。您现在看到的错误基本上是 CQL 3 的 ANTLR3 语法解析器,它不是为了接受 SELECT 批次内的查询而设计的,因为它们不受支持,您可以看到 here.
您可以预先执行 select,然后在删除时执行轻量级事务,以确保数据看起来仍然与您 select 编辑时完全一样。如果是,则您知道删除前的最新状态。如果没有,请继续重试整个过程,直到坚持下去。
如何从 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]...)
在我的用例中,我有一个主要 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 可能包含错误的数据,如果我删除了一个项目,同时删除了某人,例如点击相同项目的“赞”按钮。
deleteItem
方法执行SELECT
查询以从主 table 中获取项目的当前行
- 同时执行的
likeItem
方法运行UPDATE
查询并将项目插入owned_items_by_user
、liked_items_by_user
、... table秒。这发生在SELECT
语句执行之后,UPDATE
查询在DELETE
查询之前执行。 deleteItem
方法根据刚刚通过SELECT
陈述。该数据还不包含刚刚添加的点赞。 item因此被删除,但是刚添加的like还在liked_items_by_user
table.
遗憾的是,您不能在批处理语句中执行 SELECT
查询。如果您阅读了文档 here,则只能使用插入、更新和删除语句。
您正在寻找的是执行的原子性,但批处理语句不会成为前进的方向。如果数据已被更改,最坏的情况是僵尸或可能重新出现的数据。
Cassandra使用了一个等级周期机制来处理这个,你可以找到细节here。如果出于某种原因,这对您的业务逻辑至关重要,那么在这种情况下,您可以做的 "best" 事情是提高一致性级别,或者在应用程序级别重构读取模式以不依赖于完美的原子性,无论哪个正确的权衡是给你的。所以要么你放弃一些性能,要么调低要求。
实际上,QUORUM
应该足以满足大部分时间的大多数情况。或者,您可以执行 ALL
,并支付性能损失,但这意味着给定 foo
分区键的所有副本都必须确认 commitlog
和memtable
。请注意,这仍然意味着提交日志中的 flush
需要在删除 complete
之前发生,但您可以将一致性调整到您需要的级别。
您没有 SQL 意义上的原子性,但根据吞吐量,您不太可能需要它(碰木头)。
TLDR:
USE CONSISTENCY ALL;
DELETE FROM data_by_user WHERE user = 'foo';
这应该可以解决问题。您现在看到的错误基本上是 CQL 3 的 ANTLR3 语法解析器,它不是为了接受 SELECT 批次内的查询而设计的,因为它们不受支持,您可以看到 here.
您可以预先执行 select,然后在删除时执行轻量级事务,以确保数据看起来仍然与您 select 编辑时完全一样。如果是,则您知道删除前的最新状态。如果没有,请继续重试整个过程,直到坚持下去。