2013-06-20 38 views
2

为了避免在我的redis频道重复,我正在检查是否已经存在的消息通过在Redis中设置索引。以下是我的实施。但是,这是一个例外。Redis异常与Jedis客户端的交易

redis.clients.jedis.exceptions.JedisDataException: Please close pipeline or multi block before calling this method. 
    at redis.clients.jedis.Response.get(Response.java:23) 

这是实施。

  Jedis jedis = pool.getResource(); 

      String id = message.getId(); 
      Transaction transaction = jedis.multi(); 
      redis.clients.jedis.Response<java.lang.Boolean> response = transaction.sismember(ID_SET_REDIS_KEY, id); 
      if (response != null && !response.get().booleanValue()) { 
       //add it to the 
       transaction.sadd(ID_SET_REDIS_KEY, id); 
       transaction.publish(redisChannelName, message); 
      } 
      transaction.exec(); 
      pool.returnResource(jedis); 

因为有多个发布者可能发布完全相同的消息,所以我需要在事务内部进行获取。

回答

4

在结束交易之前,您不能让的结果得到

如果您使用的是Redis> 2.6.X,您可以使用Lua脚本来创建一个逻辑函数。请参阅Redis Lua

这正是我所做的确保我项目中的并发性。

编辑:包括更完整的示例

你应该创造这样一个PUBLISHNX脚本(未测试):

local shouldPublish = redis.call('SISMEMBER', KEYS[1], ARGV[1]) 

if shouldPublish == 0 
    redis.call('SADD', KEYS[1], ARGV[1]) 
    redis.call('PUBLISH', ARGV[2], ARGV[3]) 
end 

而且你通过所有参数必要,渠道,MESSAGEID,消息,controlKey。

PS。 Wei Li是对的,你可以使用WATCH和一个循环来实现同样的结果,以便在并发情况下重试,但我仍然更喜欢使用Lua脚本。

+1

实际上,您可以通过“WATCH”获得交易结果。 http://redis.io/topics/transactions。我不认为有必要在这里写lua脚本。 @Soumya Simanta –

1

根据上面的@Axexandre的评论,我使用下面的一段代码来执行操作。

import redis.clients.jedis.Jedis;

public class RedisLuaDemo { 

    public static void main(String args[]) 
    { 
     Jedis jedis = new Jedis("localhost"); 
     jedis.sadd("a", "b"); 
     int numberOfKeys = 1 //we are using only one Redis set 'setvar' 
     jedis.eval("if redis.call('sismember', KEYS[1], ARGV[1]) == 1 then return ARGV[2] else redis.call('sadd', KEYS[1], ARGV[1]); redis.call('publish', 'channel.mychannel', ARGV[2]) end", numberOfKeys, "setvar", "joe", "message from joe!"); 

    } 
} 

下面是有关脚本的更多信息。花了一些时间来理解语法。

if redis.call('sismember', KEYS[1], ARGV[1]) == 1 eqavalent到SISMEMBER setvar joe

redis.call('sadd', KEYS[1], ARGV[1]); 

出于某种原因,如果我没有这个jedis.sadd("a", "b");行我得到一个异常(见下文)。

Exception in thread "main" java.lang.NullPointerException 
    at redis.clients.jedis.Connection.setTimeoutInfinite(Connection.java:41) 
    at redis.clients.jedis.Jedis.eval(Jedis.java:2763) 
    at redis.RedisLuaDemo.main(RedisLuaDemo.java:13) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)