如何保持列表添加元素不重复redis?

时间:2017-08-23 17:55:06

标签: java caching redis

例如,redis上的1,2,3,4,5列表,

server1想要1到8所以它会增加6,7,8,如果成功,列表将是1,2,3,4,5,6,7,8;

server2想要1到7所以它会增加6,7,它就成功了,列表将是e 1,2,3,4,5,6,7;

你看到元素6,7在重复,所以实际上列表可能是1,2,3,4,5,6,7,8,6,7或1,2,3,4,5,6 ,7,6,7,8

我正在制作一个拖尾记录缓存,如何解决这个问题?只排序集?但缓存需要lpush

2 个答案:

答案 0 :(得分:1)

如果你真的想使用list,那么你可以添加另一个数据结构来获取一个数字是否快速存在:Set。

使您的设置数据与您的列表保持一致。当你想要一个数字到你的列表时,首先使用SISMEMBER检查该数字是否已经在集合(或列表)中,如果在,则不要LPUSH,如果不在,SADD进入set和LPUSH进入列表。 SISMEMBER是O(1),因此不会增加太多的时间成本。

需要注意的一件事:

存在一个事务问题,因为您有两个或更多服务器保持与redis的连接。所以在上面,一些动作需要是原子的。 例如,如果发生类似此订单的事情:

  

服务器1检查7使用SISMEMBER =>返回不存在

     

服务器2检查7使用SISMEMBER =>返回不存在

     

服务器1 lpush 7进入列表& sadd 7 into set

     

服务器2 lpush 7进入列表& sadd 7 into set

然后列表将有两个7。那么如何应对呢?

至少和最好,服务器检查一个号码使用SISMEMBER,如果不存在,使用SADD inser进入集合,如果存在,则不做任何设置应该是原子的。如果这是原子的,那么上面的内容将是这样的:

  

服务器1检查7使用SISMEMBER =>返回不存在&& sadd 7 into set

     

服务器2检查7使用SISMEMBER =>返回已存在。

     

server 1 lpush 7 into list

     

服务器2什么都不做

如何实现这一目标?只需使用MULTI使SISMEMBER和SADD成为原子。

MULTI
   SISMEMBER set n
   SADD set n 
EXEC

然后你可以使用SISMEMBER的回复做出决定:lpush或什么也不做。 而SADD只会忽略一个重复的元素,所以没关系。

<强> EDITED

如果您想一次性推送多个值,您可以使用pipeline来加速SISMEMBER。例如。在一个管道中:

MULTI
   SISMEMBER set n1
   SISMEMBER set n2
   ...
   SADD set n1,n2,....
EXEC

在一个回复中得到每个n的结果(存在或不存在),然后将需要被推入数组的所有值分组,lpush一起。

答案 1 :(得分:0)

排序集是开始(或甚至设置)的方式。根据其性质,列表允许重复项目。实现你想做的事情的唯一方法是使用MULTI / LREM / LPUSH / EXEC,但这是一个坏主意(LREM是O(N),随着列表的增长,这可能非常昂贵。)