Кассандра удаляет / обновляет строку и получает ее предыдущее значение - PullRequest
0 голосов
/ 27 апреля 2019

Как я могу удалить строку из 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.

Ответы [ 2 ]

2 голосов
/ 30 апреля 2019

Вы можете сделать выбор заранее, а затем выполнить легкую транзакцию при удалении, чтобы убедиться, что данные по-прежнему выглядят точно так же, как и при выборе.Если это так, вы знаете последнее состояние перед удалением.Если этого не произойдет, продолжайте повторять всю процедуру до тех пор, пока она не закроется.

0 голосов
/ 27 апреля 2019

К сожалению, вы не можете выполнить запрос SELECT внутри пакетного оператора.Если вы прочитаете документы здесь , можно использовать только операторы вставки, обновления и удаления.

Требуется атомарность выполнения, но пакетные операторы не собираютсябудьте вперед.Если данные были изменены, ваша наихудшая ситуация - это зомби или данные, которые могут появиться снова.

Кассандра использует механизм периода оценки, чтобы справиться с этим, подробности здесь .Если по какой-либо причине это имеет решающее значение для вашей бизнес-логики, «лучшее», что вы можете сделать в этой ситуации, это повысить уровень согласованности или реструктурировать шаблон чтения на уровне приложения, чтобы не полагаться на идеальную атомарность, в зависимости от того, какая сделка правильная.выкл. для вас.Так что либо вы отказываетесь от части исполнения, либо снижаете требования.

На практике QUORUM должно быть более чем достаточно для удовлетворения большинства ситуаций большую часть времени.В качестве альтернативы вы можете выполнить ALL и заплатить штраф за производительность, но это означает, что все реплики для данного ключа раздела foo должны будут подтвердить запись как в commitlog, так и в memtable.Обратите внимание, это по-прежнему означает, что flush из commitlog должно произойти до того, как удаление будет complete, но вы можете настроить согласованность на требуемый уровень.

У вас нет атомарности вСмысл SQL, но в зависимости от пропускной способности маловероятно, что он вам понадобится (коснитесь дерева).

TLDR:

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

Это должно сработать.Ошибка, которую вы видите сейчас, это в основном анализатор грамматики ANTLR3 для CQL 3, который не предназначен для приема запросов SELECT внутри пакетов просто потому, что они не поддерживаются, вы можете видеть, что здесь .

...