【问题标题】:Failed to update static column in cassandra无法更新 cassandra 中的静态列
【发布时间】:2016-02-06 12:49:16
【问题描述】:

在为具有汇款功能的简单应用程序编写一些概念证明时,我在使用 Cassandra(2.2.3 版)数据库和使用静态列时遇到了奇怪的问题。

我的桌子是:

CREATE TABLE transactions (
profile text,
timestamp timestamp,
amount text,
balance text,
lock int static,
PRIMARY KEY (profile, timestamp)) WITH CLUSTERING ORDER BY (timestamp ASC);

第一步我添加新记录

INSERT INTO transactions (profile, timestamp, amount) VALUES ( 'test_profile', '2015-11-05 15:20:01+0000', '10USD');

然后我想“锁定”当前用户交易以对他的余额进行一些操作。我尝试执行这个请求:

UPDATE transactions SET lock = 1 WHERE profile = 'test_profile' IF lock = null;

但结果是 cqlsh 我看到了

     [applied]
-----------
     False

我不明白为什么是“假”,因为个人资料的当前数据是:

 profile      | timestamp                | lock | amount | balance
--------------+--------------------------+------+--------+---------
 test_profile | 2015-11-05 15:20:01+0000 | null |  10USD |    null

知道我做错了什么吗?

更新

阅读 Nenad Bozic 的回答后,我修改了我的示例以阐明为什么我需要更新条件。完整代码示例

CREATE TABLE transactions (
    profile text,
    timestamp timestamp,
    amount text,
    balance text,
    lock int static,
    balances map<text,text> static,
    PRIMARY KEY (profile, timestamp)
) WITH CLUSTERING ORDER BY (timestamp ASC);
INSERT INTO transactions (profile, timestamp, amount) VALUES ( 'test_profile', '2015-11-05 15:20:01+0000', '1USD');
INSERT INTO transactions (profile, lock) VALUES ('test_profile', 1) IF NOT EXISTS;
BEGIN BATCH
        UPDATE transactions SET balances={'USD':'1USD'} WHERE profile='test_profile';
        UPDATE transactions SET balance='1USD' WHERE profile='test_profile' AND timestamp='2015-11-05 15:20:01+0000';
        DELETE lock FROM transactions WHERE profile='test_profile';
APPLY BATCH;

如果我再次尝试获取锁,我会得到

INSERT INTO transactions (profile, lock) VALUES ('test_profile', 1) IF NOT EXISTS;

 [applied] | profile      | timestamp | balances        | lock | amount | balance
-----------+--------------+-----------+-----------------+------+--------+---------
     False | test_profile |      null | {'USD': '1USD'} | null |   null |    null

【问题讨论】:

标签: cassandra cassandra-2.0 cql3 cqlsh nosql


【解决方案1】:

当您 INSERT 时,您没有插入 lock 字段,这意味着该字段不存在。 CQLSH 或 DevCenter 中的空表示只是合成糖,使结果看起来像表格数据,但实际上它具有动态键值,lock 不存在于该键值映射中。查看thrift representation 的数据很有用,即使它不再用于了解它是如何存储到磁盘的。

因此,当UPDATE 被触发时,它期望列存在以更新它。在您的情况下,lock 列甚至不存在,因此它无法更新它。这threadINSERTUPDATE 之间的区别也很好读。

您有两种解决方案来完成这项工作:

显式插入 null

您可以将lock 添加到您的插入语句并将其设置为 null (这在 Cassandra 中不同于将其从插入中排除,因为这样它将获得 null 值,并且当您排除它时,该列将不存在于

INSERT INTO transactions (profile, timestamp, amount, lock) 
VALUES ( 'test_profile', '2015-11-05 15:20:01+0000', '10USD', null);

在第二条语句中使用插入

由于您是第一次在第二条语句 lock 上插入而不是更新现有值,并且由于它是该分区的静态列,因此您可以使用 INSERT IF NOT EXISTS 而不是 UPDATE IF LWT 方式来执行此操作(锁定不会存在所以这将第一次通过并在所有其他时间失败,因为锁将具有价值):

INSERT INTO transactions (profile, lock) 
VALUES ('test_profile', 1) IF NOT EXISTS;

【讨论】:

  • 因为 Cassandra 中的 DELETE 不是物理删除,而是逻辑删除(列值标有 tombstone 以便下次压缩时删除)-docs.datastax.com/en/cql/3.0/cql/cql_using/use_delete.html
  • 我建议在这里使用值(锁定 = 1,未锁定 = 0 或布尔值或其他值)并基于此切换值。在第一次插入时将其设置为 0,然后使用 IF lock = 0 等进行条件更新。还要注意 Batch 只是全有或全无操作,但它不能保证语句的顺序。
  • 是的,我什么都不知道。现在我需要考虑如何在执行第一次写入时设置默认静态值以及在写入前没有任何额外读取的性能,但我认为这是一个不同的问题。我知道删除,但我认为现在 INSEER 与 IF NOT EXISTS 的工作很奇怪
猜你喜欢
  • 2015-06-12
  • 1970-01-01
  • 1970-01-01
  • 2018-01-05
  • 2013-09-18
  • 2018-04-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-31
相关资源
最近更新 更多