redis用的人很多,网络上基本都是一些入门配置。我想介绍下spring redis的实现(以接入Jedis客户端为例)。
spring redis中最主要的类就是RedisTemplate。
RedisTemplate
- RedisTemplate实现了RedisOperations,即本身就是一个Operations。
RedisTemplate序列化
Redis存储的键值都需要序列化后传输。这是因为client 和 server 间的协议要求的是 byte,而Jedis 提供了 string 和 byte[] 类型的函数接口。序列化的工具很多,RedisTemplate默认使用JdkSerializationRedisSerializer。
private boolean enableDefaultSerializer = true;
private RedisSerializer<?> defaultSerializer = new JdkSerializationRedisSerializer();
private RedisSerializer keySerializer = null;
private RedisSerializer valueSerializer = null;
private RedisSerializer hashKeySerializer = null;
private RedisSerializer hashValueSerializer = null;
private RedisSerializer<String> stringSerializer = new StringRedisSerializer();
如果要序列化的对象是String。需要使用对应的StringRedisSerializer,否则会出现\xac\xed\x00\x05t\x00\tb类似的乱码前缀。所以,要配置合适的序列化工具。
详情请看:Spring Data操作Redis时,发现key值出现\xac\xed\x00\x05t\x00\tb
RedisTemplate的操作视图
- RedisTemplate中将redis的操作进行分类(如将Value类型的操作封装在ValueOperations中,将List类型的操作封装在ListOperations中)。更方便管理,也符合人们的使用习惯。
RedisTemplate中通过如下方法获得对应的Operations。
public ValueOperations<K, V> opsForValue() {
if (valueOps == null) {
valueOps = new DefaultValueOperations(this);
}
return valueOps;
}
RedisTemplate还提供了与Operations对应的BoundValueOperations。BoundOperations绑定了key值,通过代理实现Operations的功能。
RedisTemplate中通过如下方法获得对应的BoundOperations。
public BoundValueOperations<K, V> boundValueOps(K key) {
return new DefaultBoundValueOperations(key, this);//此处将RedisTemplate对象传递给DefaultBoundValueOperations对象
}
private final ValueOperations<K, V> ops;
public DefaultBoundValueOperations(K key, RedisOperations<K, V> operations){
super(key, operations);//将RedisTemplate对象注入
ops = operations.opsForValue();
}
BoundValueOperations作为ValueOperations的代理供外部调用。
public V get() {
return (V)ops.get(getKey());
}
所以,不管是ValueOperations还是BoundValueOperations,本质上都是通过ValueOperations来操作。
我摘抄了一点DefaultValueOperations中的代码,其他的方法基本如此:
public V get(Object key)
{
return execute(new AbstractOperations.ValueDeserializingRedisCallback(this, key)
{
protected byte[] inRedis(, RedisConnection connection) {
return connection.get(rawKey);
}
}
, true);
}
由此可见,所有操作redis的操作都是在调用RedisTemplate的execute方法执行。execute方法有三类。
- public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline)
- public <T> T execute(SessionCallback<T> session)
- public List<Object> executePipelined(final SessionCallback<?> session, final RedisSerializer<?> resultSerializer)
其中,execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline)是无事物的。每次访问都到连接池拿取一个连接(池子里没有连接并且可以新建的话,就新建连接)。(此处有个是否支持事物的配置enableTransactionSupport,据说支持的不好,是个坑。未验证到底是怎么回事)
连接池根据配置信息,定时扫描检测池子里的连接。清除无用连接或多余连接,或新建连接。保证连接池的清洁有效。
execute(SessionCallback<T> session)是大家比较推崇的spring redis使用事物的方式。将连接绑定到RedisConnectionHolder上,使用结束,解绑,归还连接。此处,可以通过设置RedisConnection的watch、multi、exec指令保证数据的一致性。
executePipelined可以通过管道发送多个redis命令,这些命令会一起执行,不能互相有依赖。