2013-06-20 44 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)