第一次使用 Lettuce 5 作为 Redis 客户端,我发现简单地创建一个用于获取/设置 Redis 值为 Long 的RedisCommands<String, Long>
相当令人困惑。
我有点不清楚我如何做到这一点。据我所知,最简单的方法是使用RedisClient
重载的构造函数,它需要RedisCodec
和RedisURI
,但似乎我还需要实现编解码器解码/编码方法?
由于存储数字是 Redis 的一个相当常见的用例,我发现这种方法相当臃肿,我很惊讶没有预定义的整数/长整型编解码器。鉴于此,我怀疑可能有一个我还没有遇到的更简单的选择。有没有替代方法?
我遇到了类似的需求,最终编写了以下编解码器:
import io.lettuce.core.codec.RedisCodec;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
public class StringLongRedisCodec implements RedisCodec<String, Long> {
@Override
public String decodeKey(final ByteBuffer bytes) {
return StandardCharsets.US_ASCII.decode(bytes).toString();
}
@Override
public Long decodeValue(final ByteBuffer bytes) {
final CharBuffer charSequence = StandardCharsets.US_ASCII.decode(bytes);
return Long.parseLong(charSequence, 0, charSequence.length(), 10);
}
@Override
public ByteBuffer encodeKey(final String key) {
return StandardCharsets.US_ASCII.encode(key);
}
@Override
public ByteBuffer encodeValue(final Long value) {
return ByteBuffer.wrap(Long.toString(value).getBytes());
}
}
此链接可能会有所帮助。
它提到
Redis 以整数表示形式存储整数,因此对于实际保存整数的字符串值,存储整数的字符串表示形式不会产生任何开销。
所以我认为将整数保存为字符串是安全的。
编辑:刚刚尝试使用字符串,它有效!
以下是适用于所有本机数字类型的更全面的RedisCodec
:
import io.lettuce.core.codec.RedisCodec;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Objects;
class NumberRedisCodec implements RedisCodec<String, Number> {
@Override
public String decodeKey(ByteBuffer bytes) {
return new String(bytes.array(), StandardCharsets.UTF_8);
}
@Override
public Number decodeValue(ByteBuffer bytes) {
NumberClassEnum enumValue = NumberClassEnum.forID(bytes.get(0));
switch (enumValue) {
case BYTE:
return bytes.get(1);
case SHORT:
return bytes.getShort(1);
case INT:
return bytes.getInt(1);
case LONG:
return bytes.getLong(1);
case FLOAT:
return bytes.getFloat(1);
case DOUBLE:
return bytes.getDouble(1);
default:
throw new IllegalArgumentException("Number type not supported"); //should be unreachable
}
}
@Override
public ByteBuffer encodeKey(String key) {
return ByteBuffer.wrap(key.getBytes(StandardCharsets.UTF_8));
}
@Override
public ByteBuffer encodeValue(Number value) {
NumberClassEnum enumValue = NumberClassEnum.forClass(value.getClass());
if (Objects.isNull(enumValue)) {
throw new IllegalArgumentException("Number type not supported");
}
ByteBuffer byteBuffer = ByteBuffer.allocate(enumValue.numBytes + 1);
byteBuffer.put(0, enumValue.id);
switch (enumValue) {
case BYTE:
byteBuffer.put(value.byteValue());
break;
case SHORT:
byteBuffer.putShort(value.shortValue());
break;
case INT:
byteBuffer.putInt(value.intValue());
break;
case LONG:
byteBuffer.putLong(value.longValue());
break;
case FLOAT:
byteBuffer.putFloat(value.floatValue());
break;
case DOUBLE:
byteBuffer.putDouble(value.doubleValue());
break;
default:
throw new IllegalArgumentException("Number type not supported"); //should be unreachable
}
return byteBuffer;
}
private enum NumberClassEnum {
BYTE(Byte.class, 1, (byte) 1),
SHORT(Short.class, 2, (byte) 2),
INT(Integer.class, 4, (byte) 3),
LONG(Long.class, 8, (byte) 4),
FLOAT(Float.class, 4, (byte) 5),
DOUBLE(Double.class, 8, (byte) 6);
public final Class<? extends Number> numberClass;
public final int numBytes;
public final byte id;
private static final HashMap<Byte, NumberClassEnum> enumIDMap;
private static final HashMap<Class<? extends Number>, NumberClassEnum> enumClassMap;
static {
enumIDMap = new HashMap<>();
enumIDMap.put(BYTE.id, BYTE);
enumIDMap.put(SHORT.id, SHORT);
enumIDMap.put(INT.id, INT);
enumIDMap.put(LONG.id, LONG);
enumIDMap.put(FLOAT.id, FLOAT);
enumIDMap.put(DOUBLE.id, DOUBLE);
enumClassMap = new HashMap<>();
enumClassMap.put(BYTE.numberClass, BYTE);
enumClassMap.put(SHORT.numberClass, SHORT);
enumClassMap.put(INT.numberClass, INT);
enumClassMap.put(LONG.numberClass, LONG);
enumClassMap.put(FLOAT.numberClass, FLOAT);
enumClassMap.put(DOUBLE.numberClass, DOUBLE);
}
public static NumberClassEnum forID(byte id) {
return enumIDMap.get(id);
}
public static NumberClassEnum forClass(Class<? extends Number> clazz) {
return enumClassMap.get(clazz);
}
NumberClassEnum(Class<? extends Number> numberClass, int numBytes, byte id) {
this.numberClass = numberClass;
this.numBytes = numBytes;
this.id = id;
}
}
}