diff --git a/docs/src/reference/docbook/appendix/appendix-command-reference.xml b/docs/src/reference/docbook/appendix/appendix-command-reference.xml
index bef5d3879..a8c5aeb66 100644
--- a/docs/src/reference/docbook/appendix/appendix-command-reference.xml
+++ b/docs/src/reference/docbook/appendix/appendix-command-reference.xml
@@ -94,7 +94,7 @@
PEXIPREX
PEXPIREATX
PINGX
- PSETEX-
+ PSETEXX
PSUBSCRIBEX
PTTLX
PUBLISHX
diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java
index fdb338ce3..9d2805c66 100644
--- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java
+++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java
@@ -735,6 +735,15 @@ public class DefaultStringRedisConnection implements StringRedisConnection {
delegate.setEx(key, seconds, value);
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[])
+ */
+ @Override
+ public void pSetEx(byte[] key, long milliseconds, byte[] value) {
+ delegate.pSetEx(key, milliseconds, value);
+ }
+
public Boolean setNX(byte[] key, byte[] value) {
Boolean result = delegate.setNX(key, value);
if (isFutureConversion()) {
@@ -1695,6 +1704,15 @@ public class DefaultStringRedisConnection implements StringRedisConnection {
delegate.setEx(serialize(key), seconds, serialize(value));
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.connection.StringRedisConnection#pSetEx(java.lang.String, long, java.lang.String)
+ */
+ @Override
+ public void pSetEx(String key, long seconds, String value) {
+ pSetEx(serialize(key), seconds, serialize(value));
+ }
+
public Boolean setNX(String key, String value) {
Boolean result = delegate.setNX(serialize(key), serialize(value));
if (isFutureConversion()) {
diff --git a/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java
index afc951cde..f362be751 100644
--- a/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java
+++ b/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java
@@ -87,6 +87,17 @@ public interface RedisStringCommands {
*/
void setEx(byte[] key, long seconds, byte[] value);
+ /**
+ * Set the {@code value} and expiration in {@code milliseconds} for {@code key}.
+ *
+ * @see http://redis.io/commands/psetex
+ * @param key
+ * @param milliseconds
+ * @param value
+ * @since 1.3
+ */
+ void pSetEx(byte[] key, long milliseconds, byte[] value);
+
/**
* Set multiple keys to multiple values using key-value pairs provided in {@code tuple}.
*
diff --git a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java
index ed0a62deb..20657682e 100644
--- a/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java
+++ b/src/main/java/org/springframework/data/redis/connection/StringRedisConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 the original author or authors.
+ * Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@ import org.springframework.data.redis.serializer.RedisSerializer;
* Uses a {@link RedisSerializer} underneath to perform the conversion.
*
* @author Costin Leau
+ * @author Christoph Strobl
* @see RedisCallback
* @see RedisSerializer
* @see StringRedisTemplate
@@ -93,6 +94,17 @@ public interface StringRedisConnection extends RedisConnection {
void setEx(String key, long seconds, String value);
+ /**
+ * Set the {@code value} and expiration in {@code milliseconds} for {@code key}.
+ *
+ * @see http://redis.io/commands/psetex
+ * @param key
+ * @param seconds
+ * @param value
+ * @since 1.3
+ */
+ void pSetEx(String key, long milliseconds, String value);
+
void mSetString(Map tuple);
Boolean mSetNXString(Map tuple);
diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java
index e6ad85f06..67460b754 100644
--- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java
+++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnection.java
@@ -331,6 +331,10 @@ public class JedisConnection implements RedisConnection {
return results;
}
+ private void doPipelined(Response> response) {
+ pipeline(new JedisStatusResult(response));
+ }
+
private void pipeline(FutureResult> result) {
if (isQueueing()) {
transaction(result);
@@ -339,6 +343,10 @@ public class JedisConnection implements RedisConnection {
}
}
+ private void doQueued(Response> response) {
+ transaction(new JedisStatusResult(response));
+ }
+
private void transaction(FutureResult> result) {
txResults.add(result);
}
@@ -1141,6 +1149,28 @@ public class JedisConnection implements RedisConnection {
}
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[])
+ */
+ @Override
+ public void pSetEx(byte[] key, long milliseconds, byte[] value) {
+
+ try {
+ if (isPipelined()) {
+ doPipelined(pipeline.psetex(key, (int) milliseconds, value));
+ return;
+ }
+ if (isQueueing()) {
+ doQueued(transaction.psetex(key, (int) milliseconds, value));
+ return;
+ }
+ jedis.psetex(key, (int) milliseconds, value);
+ } catch (Exception ex) {
+ throw convertJedisAccessException(ex);
+ }
+ }
+
public Boolean setNX(byte[] key, byte[] value) {
try {
if (isPipelined()) {
diff --git a/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java b/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java
index 85c4e9a42..6ecab2ee4 100644
--- a/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java
+++ b/src/main/java/org/springframework/data/redis/connection/jredis/JredisConnection.java
@@ -495,6 +495,15 @@ public class JredisConnection implements RedisConnection {
throw new UnsupportedOperationException();
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[])
+ */
+ @Override
+ public void pSetEx(byte[] key, long milliseconds, byte[] value) {
+ throw new UnsupportedOperationException();
+ }
+
public Boolean setNX(byte[] key, byte[] value) {
try {
return jredis.setnx(key, value);
diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java
index 98044a813..8cdbadc1f 100644
--- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java
+++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnection.java
@@ -56,6 +56,7 @@ import org.springframework.util.ObjectUtils;
import com.lambdaworks.redis.RedisAsyncConnection;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisException;
+import com.lambdaworks.redis.ScriptOutputType;
import com.lambdaworks.redis.SortArgs;
import com.lambdaworks.redis.ZStoreArgs;
import com.lambdaworks.redis.codec.RedisCodec;
@@ -1197,6 +1198,49 @@ public class LettuceConnection implements RedisConnection {
}
}
+ /**
+ * {@code pSetEx} is not directly supported and therefore emulated via {@literal lua script}.
+ *
+ * @since 1.3
+ * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[])
+ */
+ @Override
+ public void pSetEx(byte[] key, long milliseconds, byte[] value) {
+
+ byte[] script = createRedisScriptForPSetEx(key, milliseconds, value);
+ byte[][] emptyArgs = new byte[0][0];
+
+ try {
+ if (isPipelined()) {
+ pipeline(new LettuceStatusResult(getAsyncConnection().eval(script, ScriptOutputType.STATUS, emptyArgs,
+ emptyArgs)));
+ return;
+ }
+ if (isQueueing()) {
+ transaction(new LettuceTxStatusResult(getConnection().eval(script, ScriptOutputType.STATUS, emptyArgs,
+ emptyArgs)));
+ return;
+ }
+ this.eval(script, ReturnType.STATUS, 0);
+ } catch (Exception ex) {
+ throw convertLettuceAccessException(ex);
+ }
+ }
+
+ private byte[] createRedisScriptForPSetEx(byte[] key, long milliseconds, byte[] value) {
+
+ StringBuilder sb = new StringBuilder("return redis.call('PSETEX'");
+ sb.append(",'");
+ sb.append(new String(key));
+ sb.append("',");
+ sb.append(milliseconds);
+ sb.append(",'");
+ sb.append(new String(value));
+ sb.append("')");
+
+ return sb.toString().getBytes();
+ }
+
public Boolean setNX(byte[] key, byte[] value) {
try {
if (isPipelined()) {
diff --git a/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java b/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java
index 2aecab82d..ba7c5a6c3 100644
--- a/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java
+++ b/src/main/java/org/springframework/data/redis/connection/srp/SrpConnection.java
@@ -900,6 +900,24 @@ public class SrpConnection implements RedisConnection {
}
}
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[])
+ */
+ @Override
+ public void pSetEx(byte[] key, long milliseconds, byte[] value) {
+
+ try {
+ if (isPipelined()) {
+ doPipelined(pipeline.psetex(key, milliseconds, value));
+ return;
+ }
+ client.psetex(key, milliseconds, value);
+ } catch (Exception ex) {
+ throw convertSrpAccessException(ex);
+ }
+ }
+
public Boolean setNX(byte[] key, byte[] value) {
try {
if (isPipelined()) {
@@ -2113,6 +2131,11 @@ public class SrpConnection implements RedisConnection {
}
}
+ @SuppressWarnings("rawtypes")
+ private void doPipelined(ListenableFuture listenableFuture) {
+ pipeline(new SrpStatusResult(listenableFuture));
+ }
+
// processing method that adds a listener to the future in order to track down the results and close the pipeline
private void pipeline(FutureResult> future) {
if (isQueueing()) {
diff --git a/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java
index 1e148b426..bdfaf8d2c 100644
--- a/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java
+++ b/src/main/java/org/springframework/data/redis/core/DefaultValueOperations.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 the original author or authors.
+ * Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ import org.springframework.data.redis.connection.RedisConnection;
*
* @author Costin Leau
* @author Jennifer Hickey
+ * @author Christoph Strobl
*/
class DefaultValueOperations extends AbstractOperations implements ValueOperations {
@@ -173,17 +174,37 @@ class DefaultValueOperations extends AbstractOperations implements V
}, true);
}
- public void set(K key, V value, long timeout, TimeUnit unit) {
+ public void set(K key, V value, final long timeout, final TimeUnit unit) {
final byte[] rawKey = rawKey(key);
final byte[] rawValue = rawValue(value);
- final long rawTimeout = TimeoutUtils.toSeconds(timeout, unit);
execute(new RedisCallback