diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java index 29b1b5336..e41c49e01 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.springframework.dao.DataAccessException; import org.springframework.data.keyvalue.redis.connection.RedisConnection; import org.springframework.data.keyvalue.redis.connection.RedisConnectionFactory; import org.springframework.data.keyvalue.redis.serializer.RedisSerializer; @@ -320,7 +321,13 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @Override public Object exec() { - throw new UnsupportedOperationException(); + return execute(new RedisCallback() { + + @Override + public Object doInRedis(RedisConnection connection) throws DataAccessException { + return connection.exec(); + } + }); } @Override @@ -379,7 +386,13 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @Override public void multi() { - throw new UnsupportedOperationException(); + execute(new RedisCallback() { + @Override + public Object doInRedis(RedisConnection connection) throws DataAccessException { + connection.multi(); + return null; + } + }, true); } @Override diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java index 6b18ae8f7..d490ac7a4 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java @@ -83,15 +83,6 @@ public class DefaultRedisMap implements RedisMap { return hashOps.increment(key, delta); } - @Override - public boolean putIfAbsent(K key, V value) { - if (!hashOps.hasKey(key)) { - put(key, value); - return true; - } - return false; - } - @Override public String getKey() { return hashOps.getKey(); @@ -203,4 +194,104 @@ public class DefaultRedisMap implements RedisMap { sb.append(getKey()); return sb.toString(); } + + @Override + public V putIfAbsent(K key, V value) { + throw new UnsupportedOperationException(); + + // RedisOperations ops = hashOps.getOperations(); + // + // for (;;) { + // ops.watch(getKey()); + // V v = get(key); + // if (v == null) { + // ops.multi(); + // put(key, value); + // if (ops.exec() != null) { + // return null; + // } + // } + // else { + // return v; + // } + // } + } + + @Override + public boolean remove(Object key, Object value) { + throw new UnsupportedOperationException(); + + // if (value == null){ + // throw new NullPointerException(); + // } + // + // RedisOperations ops = hashOps.getOperations(); + // + // for (;;) { + // ops.watch(getKey()); + // V v = get(key); + // if (value.equals(v)) { + // ops.multi(); + // remove(key); + // if (ops.exec() != null) { + // return true; + // } + // } + // else { + // return false; + // } + // } + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw new UnsupportedOperationException(); + + // if (newValue == null || oldValue == null) { + // throw new NullPointerException(); + // } + // + // RedisOperations ops = hashOps.getOperations(); + // + // for (;;) { + // ops.watch(getKey()); + // V v = get(key); + // if (oldValue.equals(v)) { + // ops.multi(); + // put(key, newValue); + // if (ops.exec() != null) { + // return true; + // } + // } + // else { + // return false; + // } + // } + } + + @Override + public V replace(K key, V value) { + throw new UnsupportedOperationException(); + + + // if (value == null) { + // throw new NullPointerException(); + // } + // + // RedisOperations ops = hashOps.getOperations(); + // + // for (;;) { + // ops.watch(getKey()); + // if (containsKey(key)) { + // ops.multi(); + // V oldValue = put(key, value); + // if (ops.exec() != null) { + // return oldValue; + // } + // } + // else { + // return null; + // } + // } + } } \ No newline at end of file diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisAtomicInteger.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisAtomicInteger.java index 7fbd1ee00..39a08d63d 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisAtomicInteger.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisAtomicInteger.java @@ -100,7 +100,9 @@ public class RedisAtomicInteger extends Number implements Serializable { return true; } } - return false; + else { + return false; + } } } diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisAtomicLong.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisAtomicLong.java index d7d32f56b..007062a3e 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisAtomicLong.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisAtomicLong.java @@ -101,7 +101,9 @@ public class RedisAtomicLong extends Number implements Serializable { return true; } } - return false; + else { + return false; + } } } diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisMap.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisMap.java index cdbf4fd82..83e1ca52e 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisMap.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/RedisMap.java @@ -15,16 +15,15 @@ */ package org.springframework.data.keyvalue.redis.util; -import java.util.Map; +import java.util.concurrent.ConcurrentMap; + /** * Map view of a Redis hash. * * @author Costin Leau */ -public interface RedisMap extends RedisStore, Map { - - boolean putIfAbsent(K key, V value); +public interface RedisMap extends RedisStore, ConcurrentMap { Integer increment(K key, int delta); } diff --git a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java index 3a5d210b8..ab67e738b 100644 --- a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java +++ b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java @@ -269,25 +269,6 @@ public abstract class AbstractRedisMapTests { assertEquals(v2, map.get(k2)); } - @Test - public void testPutIfAbsent() { - K k1 = getKey(); - K k2 = getKey(); - - V v1 = getValue(); - V v2 = getValue(); - - assertNull(map.get(k1)); - assertTrue(map.putIfAbsent(k1, v1)); - assertFalse(map.putIfAbsent(k1, v2)); - assertEquals(v1, map.get(k1)); - - assertTrue(map.putIfAbsent(k2, v2)); - assertFalse(map.putIfAbsent(k2, v1)); - - assertEquals(v2, map.get(k2)); - } - @Test public void testRemove() { K k1 = getKey(); @@ -375,4 +356,65 @@ public abstract class AbstractRedisMapTests { assertThat(values, hasItem(v1)); assertThat(values, not(hasItem(v2))); } + + + @Test(expected = UnsupportedOperationException.class) + public void testConcurrentPutIfAbsent() { + K k1 = getKey(); + K k2 = getKey(); + + V v1 = getValue(); + V v2 = getValue(); + + assertNull(map.get(k1)); + assertNull(map.putIfAbsent(k1, v1)); + assertEquals(v1, map.putIfAbsent(k1, v2)); + assertEquals(v1, map.get(k1)); + + assertNull(map.putIfAbsent(k2, v2)); + assertEquals(v2, map.putIfAbsent(k2, v1)); + + assertEquals(v2, map.get(k2)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testConcurrentRemove() { + K k1 = getKey(); + V v1 = getValue(); + V v2 = getValue(); + + map.put(k1, v1); + assertFalse(map.remove(k1, v1)); + assertEquals(v1, map.get(k1)); + assertTrue(map.remove(k1, v1)); + assertNull(map.get(k1)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testConcurrentReplaceTwoArgs() { + K k1 = getKey(); + V v1 = getValue(); + V v2 = getValue(); + + map.put(k1, v1); + + assertFalse(map.replace(k1, v2, v1)); + assertEquals(v1, map.get(k1)); + assertTrue(map.replace(k1, v1, v2)); + assertEquals(v2, map.get(k1)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testConcurrentReplaceOneArg() { + K k1 = getKey(); + V v1 = getValue(); + V v2 = getValue(); + + assertNull(map.replace(k1, v1)); + map.put(k1, v1); + assertNull(map.replace(getKey(), v1)); + assertEquals(v1, map.replace(k1, v2)); + assertEquals(v2, map.get(k1)); + + } } \ No newline at end of file