Cassandra防止重复

问题描述 投票:5回答:3

我有一个简单的表格,由 userId:

create table test (
  userId uuid,
  placeId uuid,
  visitTime timestamp,
  primary key(userId, placeId, visitTime)
) with clustering order by (placeId asc, visitTime desc);

每对 (userId, placeId) 可以有1次或没有访问。visitTime 只是一些与之相关的数据,用于在查询中进行排序,如 select * from test where userId = ? order by visitTime desc.

我怎么能要求 (userId, placeId) 要做到独一无二?我需要确保

insert into test (userId, placeId, timeVisit) values (?, ?, ?)

不会插入第二次访问 (userId, placeId) 用不同的时间。插入前检查是否存在不是原子,有没有更好的方法?

cassandra cql cql3
3个回答
7
投票

让我明白--如果这对情侣 (userId, placeId) 应该是唯一的,(意思是你不必把两行与这对数据)什么是 timeVisit 在主键中有用吗?为什么要使用 order by visitTime desc 如果这将只有一行?

如果你需要的是防止重复,你有2种方法。

1 - 轻量级事务 -- 这个,使用 IF NOT EXISTS 会做你想要的事情。但正如我所解释的 此处 由于cassandra的特殊处理方式,轻量级事务真的很慢

2 - USING TIMESTAMP 写时间的执行--(要小心!***)的'窍门'是强行递减 TIMESTAMP

让我举个例子。

INSERT INTO users (uid, placeid , visittime , otherstuffs ) VALUES ( 1, 2, 1000, 'PLEASE DO NOT OVERWRITE ME') using TIMESTAMP 100;

这将产生这样的输出

select * from users;

 uid | placeid | otherstuffs                | visittime
-----+---------+----------------------------+-----------
   1 |       2 | PLEASE DO NOT OVERWRITE ME |      1000

现在让我们减少 timestamp

INSERT INTO users (uid, placeid , visittime , otherstuffs ) VALUES ( 1, 2, 2000, 'I WANT OVERWRITE YOU') using TIMESTAMP 90;

现在表中的数据还没有更新由于夫妻双方有较高的TS操作(100)。(uid, placeid) -- 事实上,这里的产出没有改变

select * from users;

 uid | placeid | otherstuffs                | visittime
-----+---------+----------------------------+-----------
   1 |       2 | PLEASE DO NOT OVERWRITE ME |      1000

如果性能很重要,那就用解决方案2,如果性能不重要,那就用解决方案1。对于解决方案2,你可以用一个固定的数字减去系统时间毫秒,计算出每次写入的时间戳递减。

例如: *** 这个解决方案可能会导致意外的行为,例如,如果你想先删除然后再重新插入数据。

Long decreasingTimestamp = 2_000_000_000_000L - System.currentTimeMillis();

*** 这一解决办法可能会导致意外的行为,例如,如果你想删除然后重新插入数据。重要的是,一旦你删除了数据,你将能够再次写入它们,只有当写入操作的时间戳高于删除操作的时间戳(如果没有指定,使用的时间戳是机器的时间戳)。

HTH, Carlo


1
投票

在Cassandra中,每个主键(行键+聚类键)组合都是唯一的。因此,如果你有一个主键为(A,B,C)的条目,而你插入另一个新的条目,具有相同的(A,B,C)值,旧的条目将被覆盖。

在你的情况下,你的主键中有一个timeVisit属性,这使得在你的情况下无法使用。你可能需要重新考虑你的方案,所以你不需要timeVisit属性。


0
投票

如果我正确理解了你的要求,你并不真的需要 "时间访问 "属性。visitTime 作为主键的一部分。在你的查询中,你也不需要按主键的 visitTime 因为总是只有一个出现的。userIdplaceId 组合。你不需要插入一个没有 "记录 "的 "记录"。visitTime 因为你可以放心地假设,如果你的查询返回0个结果,那么用户从未访问过这个地方。

所以如果你把你的 PRIMARY KEY 只不过 userId, placeId 那么你可以使用 轻量级交易 来实现你的目标。

你可以使用简单的 insert into test (userId, placeId, timeVisit) values (?, ?, ?) IF NOT EXISTS的记录,如果已经有一条记录带有所提供的 userIdplaceId 组合。

© www.soinside.com 2019 - 2024. All rights reserved.