无法更新 cassandra 中的静态列
Failed to update static column in cassandra
我在使用 Cassandra(版本 2.2.3)数据库和使用静态列时遇到奇怪的问题,当我为具有汇款功能的简单应用程序编写一些概念证明时。
我的table是:
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');
然后我想'lock'当前用户交易用他的余额做一些动作。我尝试执行这个请求:
UPDATE transactions SET lock = 1 WHERE profile = 'test_profile' IF lock = null;
但是我看到了 cqlsh 的结果
[applied]
-----------
False
我不明白为什么 '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
当你INSERT
时你没有插入lock
字段,这意味着这个字段不存在。 CQLSH 或 DevCenter 中的空表示只是合成糖,使结果看起来像表格数据,但实际上它具有动态键值,并且 lock
不存在于该键值映射中。查看 thrift representation 数据很有用,即使它不再被使用以了解它是如何存储到磁盘的。
所以当 UPDATE
被触发时,它期望列存在以更新它。在您的情况下 lock
列甚至不存在,因此无法更新它。关于 INSERT
和 UPDATE
之间差异的 thread 也很好读。
你有两个解决方案来完成这项工作:
显式插入 null
您可以将 lock
添加到您的插入语句并将其设置为空(这在 Cassandra 中不同于将其从插入中排除,因为这样它将获得空值,并且当您排除它时,该列不会存在于
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(版本 2.2.3)数据库和使用静态列时遇到奇怪的问题,当我为具有汇款功能的简单应用程序编写一些概念证明时。
我的table是:
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');
然后我想'lock'当前用户交易用他的余额做一些动作。我尝试执行这个请求:
UPDATE transactions SET lock = 1 WHERE profile = 'test_profile' IF lock = null;
但是我看到了 cqlsh 的结果
[applied]
-----------
False
我不明白为什么 '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
当你INSERT
时你没有插入lock
字段,这意味着这个字段不存在。 CQLSH 或 DevCenter 中的空表示只是合成糖,使结果看起来像表格数据,但实际上它具有动态键值,并且 lock
不存在于该键值映射中。查看 thrift representation 数据很有用,即使它不再被使用以了解它是如何存储到磁盘的。
所以当 UPDATE
被触发时,它期望列存在以更新它。在您的情况下 lock
列甚至不存在,因此无法更新它。关于 INSERT
和 UPDATE
之间差异的 thread 也很好读。
你有两个解决方案来完成这项工作:
显式插入 null
您可以将 lock
添加到您的插入语句并将其设置为空(这在 Cassandra 中不同于将其从插入中排除,因为这样它将获得空值,并且当您排除它时,该列不会存在于
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;