为了避免我的redis频道重复,我通过在Redis中设置索引来检查消息是否已存在。以下是我的实施。但是,这是一个例外。
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);
我需要进行交易,因为有多个发布商可能会发布完全相同的消息。
答案 0 :(得分:4)
在结束交易之前,您无法获得获取的结果。
如果您使用的是Redis&gt; 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
然后传递所有必要的参数,channel,messageId,message,controlKey。
PS。 Wei Li是对的,你可以使用WATCH和循环来实现相同的结果,以便在并发的情况下重试,但我仍然喜欢使用Lua脚本。
答案 1 :(得分:1)
基于@ Axexandre上面的评论,我使用以下代码来执行操作。
导入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
与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)