#### env:${env}
redis.maxIdle=80
##最小空闲数
redis.minIdle=10
##最大连接数:能够同时建立的“最大链接个数”
redis.maxTotal=500
#每次最大连接数
redis.numTestsPerEvictionRun=1024
##最大建立连接等待时间:单位ms
##当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException;
redis.maxWait=5000
##使用连接时,检测连接是否成功
redis.testOnBorrow=true
#连接耗尽时是否阻塞,false报异常,true阻塞超时,默认true
redis.blockWhenExhausted=false
##在return给pool时,是否提前进行validate操作
redis.testOnReturn=true
##当客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能,单位毫秒
redis.timeout=3000
#在空闲时检查有效性,默认false
redis.testWhileIdle=true
#连接的最小空闲时间,连接池中连接可空闲的时间
redis.minEvictableIdleTimeMills=30000
#释放扫描的扫描间隔,单位毫秒数;检查一次连接池中空闲的连接,把空闲时间超过minEvictableIdleTimeMillis毫秒的连接断开,直到连接池中的连接数到minIdle为止
redis.timeBetweenEvictionRunsMillis=60000
一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才是可序列化的。因此如果要序列化某些类的对象,这些类就必须实现Serializable接口。而实际上,Serializable是一个空接口,没有什么具体内容,它的目的只是简单的标识一个类的对象可以被序列化。
什么情况下需要序列化:
1. 当你想把的内存中的对象写入到硬盘的时候。
2. 当你想用套接字在网络上传送对象的时候。
3. 当你想通过RMI传输对象的时候。
Spring针对Redis的使用,封装了一个比较强大的Template以方便使用;之前在Spring的生态圈中也使用过redis,但直接使用Jedis进行相应的交互操作,现在正好来看一下RedisTemplate是怎么实现的,以及使用起来是否更加便利
redis.hostName=127.0.0.1
redis.port=6379
redis.password=https://blog.hhui.top
# 连接超时时间
redis.timeout=10000
#最大空闲数
redis.maxIdle=300
#控制一个pool可分配多少个jedis实例,用来替换上面的redis.maxActive,如果是jedis 2.4以后用该属性
redis.maxTotal=1000
#最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
redis.maxWaitMillis=1000
#连接的最小空闲时间 默认1800000毫秒(30分钟)
redis.minEvictableIdleTimeMillis=300000
#每次释放连接的最大数目,默认3
redis.numTestsPerEvictionRun=1024
#逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
redis.timeBetweenEvictionRunsMillis=30000
#是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
redis.testOnBorrow=true
#在空闲时检查有效性, 默认false
redis.testWhileIdle=true
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.data.redis.core;
import java.io.Closeable;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.SortParameters;
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.data.redis.core.query.QueryUtils;
import org.springframework.data.redis.core.query.SortQuery;
import org.springframework.data.redis.core.script.DefaultScriptExecutor;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.core.script.ScriptExecutor;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationUtils;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
private boolean enableTransactionSupport = false;
private boolean exposeConnection = false;
private boolean initialized = false;
private boolean enableDefaultSerializer = true;
private RedisSerializer<?> defaultSerializer;
private ClassLoader classLoader;
private RedisSerializer keySerializer = null;
private RedisSerializer valueSerializer = null;
private RedisSerializer hashKeySerializer = null;
private RedisSerializer hashValueSerializer = null;
private RedisSerializer<String> stringSerializer = new StringRedisSerializer();
private ScriptExecutor<K> scriptExecutor;
private ValueOperations<K, V> valueOps;
private ListOperations<K, V> listOps;
private SetOperations<K, V> setOps;
private ZSetOperations<K, V> zSetOps;
private GeoOperations<K, V> geoOps;
private HyperLogLogOperations<K, V> hllOps;
public RedisTemplate() {
}
//afterPropertiesSet (初始化操作)加载配置后执行
public void afterPropertiesSet() {
super.afterPropertiesSet();
boolean defaultUsed = false;
//serializer 序列化
if (this.defaultSerializer == null) {
this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
}
//enable 使能够,提供做…的权利[措施]; 使可能; 授予权利或方法;
if (this.enableDefaultSerializer) {
if (this.keySerializer == null) {
this.keySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.valueSerializer == null) {
this.valueSerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashKeySerializer == null) {
this.hashKeySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashValueSerializer == null) {
this.hashValueSerializer = this.defaultSerializer;
defaultUsed = true;
}
}
if (this.enableDefaultSerializer && defaultUsed) {
Assert.notNull(this.defaultSerializer, "default serializer null and not all serializers initialized");
}
//script脚本
//Executor 遗嘱执行人; 执行者; 实行者;
if (this.scriptExecutor == null) {
this.scriptExecutor = new DefaultScriptExecutor(this);
}
//初始化完成
this.initialized = true;
}
//execute 执行 exposeConnection暴露连接
public <T> T execute(RedisCallback<T> action) {
return this.execute(action, this.isExposeConnection());
}
public <T> T execute(RedisCallback<T> action, boolean exposeConnection) {
return this.execute(action, exposeConnection, false);
}
//pipeline 管道
public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
Assert.isTrue(this.initialized, "template not initialized; call afterPropertiesSet() before using it");
Assert.notNull(action, "Callback object must not be null");
RedisConnectionFactory factory = this.getConnectionFactory();
RedisConnection conn = null;
Object var11;
try {
//enableTransactionSupport 是否支持事务
if (this.enableTransactionSupport) {
conn = RedisConnectionUtils.bindConnection(factory, this.enableTransactionSupport);
} else {
conn = RedisConnectionUtils.getConnection(factory);
}
//现存的; 目前的;
boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);
RedisConnection connToUse = this.preProcessConnection(conn, existingConnection);
boolean pipelineStatus = connToUse.isPipelined();
if (pipeline && !pipelineStatus) {
connToUse.openPipeline();
}
RedisConnection connToExpose = exposeConnection ? connToUse : this.createRedisConnectionProxy(connToUse);
T result = action.doInRedis(connToExpose);
if (pipeline && !pipelineStatus) {
connToUse.closePipeline();
}
var11 = this.postProcessResult(result, connToUse, existingConnection);
} finally {
RedisConnectionUtils.releaseConnection(conn, factory);
}
return var11;
}
public <T> T execute(SessionCallback<T> session) {
Assert.isTrue(this.initialized, "template not initialized; call afterPropertiesSet() before using it");
Assert.notNull(session, "Callback object must not be null");
RedisConnectionFactory factory = this.getConnectionFactory();
RedisConnectionUtils.bindConnection(factory, this.enableTransactionSupport);
Object var3;
try {
var3 = session.execute(this);
} finally {
RedisConnectionUtils.unbindConnection(factory);
}
return var3;
}
//executePipelined 执行管道
public List<Object> executePipelined(SessionCallback<?> session) {
return this.executePipelined(session, this.valueSerializer);
}
public List<Object> executePipelined(final SessionCallback<?> session, final RedisSerializer<?> resultSerializer) {
Assert.isTrue(this.initialized, "template not initialized; call afterPropertiesSet() before using it");
Assert.notNull(session, "Callback object must not be null");
RedisConnectionFactory factory = this.getConnectionFactory();
RedisConnectionUtils.bindConnection(factory, this.enableTransactionSupport);
List var4;
try {
var4 = (List)this.execute(new RedisCallback<List<Object>>() {
public List<Object> doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
boolean pipelinedClosed = false;
List var5;
try {
Object result = RedisTemplate.this.executeSession(session);
if (result != null) {
throw new InvalidDataAccessApiUsageException("Callback cannot return a non-null value as it gets overwritten by the pipeline");
}
List<Object> closePipeline = connection.closePipeline();
pipelinedClosed = true;
var5 = RedisTemplate.this.deserializeMixedResults(closePipeline, resultSerializer, RedisTemplate.this.hashKeySerializer, RedisTemplate.this.hashValueSerializer);
} finally {
if (!pipelinedClosed) {
connection.closePipeline();
}
}
return var5;
}
});
} finally {
RedisConnectionUtils.unbindConnection(factory);
}
return var4;
}
public List<Object> executePipelined(RedisCallback<?> action) {
return this.executePipelined(action, this.valueSerializer);
}
public List<Object> executePipelined(final RedisCallback<?> action, final RedisSerializer<?> resultSerializer) {
return (List)this.execute(new RedisCallback<List<Object>>() {
public List<Object> doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
boolean pipelinedClosed = false;
List var5;
try {
Object result = action.doInRedis(connection);
if (result != null) {
throw new InvalidDataAccessApiUsageException("Callback cannot return a non-null value as it gets overwritten by the pipeline");
}
List<Object> closePipeline = connection.closePipeline();
pipelinedClosed = true;
var5 = RedisTemplate.this.deserializeMixedResults(closePipeline, resultSerializer, RedisTemplate.this.hashKeySerializer, RedisTemplate.this.hashValueSerializer);
} finally {
if (!pipelinedClosed) {
connection.closePipeline();
}
}
return var5;
}
});
}
public <T> T execute(RedisScript<T> script, List<K> keys, Object... args) {
return this.scriptExecutor.execute(script, keys, args);
}
public <T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSerializer<T> resultSerializer, List<K> keys, Object... args) {
return this.scriptExecutor.execute(script, argsSerializer, resultSerializer, keys, args);
}
public <T extends Closeable> T executeWithStickyConnection(RedisCallback<T> callback) {
Assert.isTrue(this.initialized, "template not initialized; call afterPropertiesSet() before using it");
Assert.notNull(callback, "Callback object must not be null");
RedisConnectionFactory factory = this.getConnectionFactory();
RedisConnection connection = this.preProcessConnection(RedisConnectionUtils.doGetConnection(factory, true, false, false), false);
return (Closeable)callback.doInRedis(connection);
}
//Session会话
private Object executeSession(SessionCallback<?> session) {
return session.execute(this);
}
//Proxy 代理服务器; 代表权; 代理人,代替物; 委托书;
protected RedisConnection createRedisConnectionProxy(RedisConnection pm) {
Class<?>[] ifcs = ClassUtils.getAllInterfacesForClass(pm.getClass(), this.getClass().getClassLoader());
return (RedisConnection)Proxy.newProxyInstance(pm.getClass().getClassLoader(), ifcs, new CloseSuppressingInvocationHandler(pm));
}
protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
return connection;
}
protected <T> T postProcessResult(T result, RedisConnection conn, boolean existingConnection) {
return result;
}
public boolean isExposeConnection() {
return this.exposeConnection;
}
public void setExposeConnection(boolean exposeConnection) {
this.exposeConnection = exposeConnection;
}
//是否默认序列化
public boolean isEnableDefaultSerializer() {
return this.enableDefaultSerializer;
}
public void setEnableDefaultSerializer(boolean enableDefaultSerializer) {
this.enableDefaultSerializer = enableDefaultSerializer;
}
public RedisSerializer<?> getDefaultSerializer() {
return this.defaultSerializer;
}
public void setDefaultSerializer(RedisSerializer<?> serializer) {
this.defaultSerializer = serializer;
}
public void setKeySerializer(RedisSerializer<?> serializer) {
this.keySerializer = serializer;
}
public RedisSerializer<?> getKeySerializer() {
return this.keySerializer;
}
public void setValueSerializer(RedisSerializer<?> serializer) {
this.valueSerializer = serializer;
}
public RedisSerializer<?> getValueSerializer() {
return this.valueSerializer;
}
public RedisSerializer<?> getHashKeySerializer() {
return this.hashKeySerializer;
}
public void setHashKeySerializer(RedisSerializer<?> hashKeySerializer) {
this.hashKeySerializer = hashKeySerializer;
}
public RedisSerializer<?> getHashValueSerializer() {
return this.hashValueSerializer;
}
public void setHashValueSerializer(RedisSerializer<?> hashValueSerializer) {
this.hashValueSerializer = hashValueSerializer;
}
public RedisSerializer<String> getStringSerializer() {
return this.stringSerializer;
}
public void setStringSerializer(RedisSerializer<String> stringSerializer) {
this.stringSerializer = stringSerializer;
}
public void setScriptExecutor(ScriptExecutor<K> scriptExecutor) {
this.scriptExecutor = scriptExecutor;
}
private byte[] rawKey(Object key) {
Assert.notNull(key, "non null key required");
return this.keySerializer == null && key instanceof byte[] ? (byte[])((byte[])key) : this.keySerializer.serialize(key);
}
private byte[] rawString(String key) {
return this.stringSerializer.serialize(key);
}
private byte[] rawValue(Object value) {
return this.valueSerializer == null && value instanceof byte[] ? (byte[])((byte[])value) : this.valueSerializer.serialize(value);
}
private byte[][] rawKeys(Collection<K> keys) {
byte[][] rawKeys = new byte[keys.size()][];
int i = 0;
Object key;
for(Iterator var4 = keys.iterator(); var4.hasNext(); rawKeys[i++] = this.rawKey(key)) {
key = var4.next();
}
return rawKeys;
}
//deserializeKey 反序列化
private K deserializeKey(byte[] value) {
return this.keySerializer != null ? this.keySerializer.deserialize(value) : value;
}
private List<Object> deserializeMixedResults(List<Object> rawValues, RedisSerializer valueSerializer, RedisSerializer hashKeySerializer, RedisSerializer hashValueSerializer) {
if (rawValues == null) {
return null;
} else {
List<Object> values = new ArrayList();
Iterator var6 = rawValues.iterator();
while(true) {
while(var6.hasNext()) {
Object rawValue = var6.next();
if (rawValue instanceof byte[] && valueSerializer != null) {
values.add(valueSerializer.deserialize((byte[])((byte[])rawValue)));
} else if (rawValue instanceof List) {
values.add(this.deserializeMixedResults((List)rawValue, valueSerializer, hashKeySerializer, hashValueSerializer));
} else if (rawValue instanceof Set && !((Set)rawValue).isEmpty()) {
values.add(this.deserializeSet((Set)rawValue, valueSerializer));
} else if (rawValue instanceof Map && !((Map)rawValue).isEmpty() && ((Map)rawValue).values().iterator().next() instanceof byte[]) {
values.add(SerializationUtils.deserialize((Map)rawValue, hashKeySerializer, hashValueSerializer));
} else {
values.add(rawValue);
}
}
return values;
}
}
}
private Set<?> deserializeSet(Set rawSet, RedisSerializer valueSerializer) {
if (rawSet.isEmpty()) {
return rawSet;
} else {
Object setValue = rawSet.iterator().next();
if (setValue instanceof byte[] && valueSerializer != null) {
return SerializationUtils.deserialize(rawSet, valueSerializer);
} else {
return setValue instanceof Tuple ? this.convertTupleValues(rawSet, valueSerializer) : rawSet;
}
}
}
//拼装数组值
private Set<TypedTuple<V>> convertTupleValues(Set<Tuple> rawValues, RedisSerializer valueSerializer) {
Set<TypedTuple<V>> set = new LinkedHashSet(rawValues.size());
Tuple rawValue;
Object value;
for(Iterator var4 = rawValues.iterator(); var4.hasNext(); set.add(new DefaultTypedTuple(value, rawValue.getScore()))) {
rawValue = (Tuple)var4.next();
value = rawValue.getValue();
if (valueSerializer != null) {
value = valueSerializer.deserialize(rawValue.getValue());
}
}
return set;
}
public List<Object> exec() {
List<Object> results = this.execRaw();
return this.getConnectionFactory().getConvertPipelineAndTxResults() ? this.deserializeMixedResults(results, this.valueSerializer, this.hashKeySerializer, this.hashValueSerializer) : results;
}
public List<Object> exec(RedisSerializer<?> valueSerializer) {
return this.deserializeMixedResults(this.execRaw(), valueSerializer, valueSerializer, valueSerializer);
}
protected List<Object> execRaw() {
return (List)this.execute(new RedisCallback<List<Object>>() {
public List<Object> doInRedis(RedisConnection connection) throws DataAccessException {
return connection.exec();
}
});
}
//删除,根据键删除值
public void delete(K key) {
final byte[] rawKey = this.rawKey(key);
this.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) {
connection.del(new byte[][]{rawKey});
return null;
}
}, true);
}
//删除,根据键的集合,批量删除值
public void delete(Collection<K> keys) {
if (!CollectionUtils.isEmpty(keys)) {
final byte[][] rawKeys = this.rawKeys(keys);
this.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) {
connection.del(rawKeys);
return null;
}
}, true);
}
}
//是否含有指定的键
public Boolean hasKey(K key) {
final byte[] rawKey = this.rawKey(key);
return (Boolean)this.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) {
return connection.exists(rawKey);
}
}, true);
}
//缓存是否过期
//expire 期满; 文件、协议等(因到期而)失效; 断气; 逝世;
public Boolean expire(K key, final long timeout, final TimeUnit unit) {
final byte[] rawKey = this.rawKey(key);
final long rawTimeout = TimeoutUtils.toMillis(timeout, unit);
return (Boolean)this.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) {
try {
return connection.pExpire(rawKey, rawTimeout);
} catch (Exception var3) {
return connection.expire(rawKey, TimeoutUtils.toSeconds(timeout, unit));
}
}
}, true);
}
public Boolean expireAt(K key, final Date date) {
final byte[] rawKey = this.rawKey(key);
return (Boolean)this.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) {
try {
return connection.pExpireAt(rawKey, date.getTime());
} catch (Exception var3) {
return connection.expireAt(rawKey, date.getTime() / 1000L);
}
}
}, true);
}
//订阅发布
public void convertAndSend(String channel, Object message) {
Assert.hasText(channel, "a non-empty channel is required");
final byte[] rawChannel = this.rawString(channel);
final byte[] rawMessage = this.rawValue(message);
this.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) {
connection.publish(rawChannel, rawMessage);
return null;
}
}, true);
}
public Long getExpire(K key) {
final byte[] rawKey = this.rawKey(key);
return (Long)this.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) {
return connection.ttl(rawKey);
}
}, true);
}
public Long getExpire(K key, final TimeUnit timeUnit) {
final byte[] rawKey = this.rawKey(key);
return (Long)this.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) {
try {
return connection.pTtl(rawKey, timeUnit);
} catch (Exception var3) {
return connection.ttl(rawKey, timeUnit);
}
}
}, true);
}
public Set<K> keys(K pattern) {
final byte[] rawKey = this.rawKey(pattern);
Set<byte[]> rawKeys = (Set)this.execute(new RedisCallback<Set<byte[]>>() {
public Set<byte[]> doInRedis(RedisConnection connection) {
return connection.keys(rawKey);
}
}, true);
return this.keySerializer != null ? SerializationUtils.deserialize(rawKeys, this.keySerializer) : rawKeys;
}
//持久化
//persist:坚持; 存留; 固执; 继续存在;
public Boolean persist(K key) {
final byte[] rawKey = this.rawKey(key);
return (Boolean)this.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) {
return connection.persist(rawKey);
}
}, true);
}
//move移动
public Boolean move(K key, final int dbIndex) {
final byte[] rawKey = this.rawKey(key);
return (Boolean)this.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) {
return connection.move(rawKey, dbIndex);
}
}, true);
}
//获取随机key值
public K randomKey() {
byte[] rawKey = (byte[])this.execute(new RedisCallback<byte[]>() {
public byte[] doInRedis(RedisConnection connection) {
return connection.randomKey();
}
}, true);
return this.deserializeKey(rawKey);
}
//key值重命名
public void rename(K oldKey, K newKey) {
final byte[] rawOldKey = this.rawKey(oldKey);
final byte[] rawNewKey = this.rawKey(newKey);
this.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) {
connection.rename(rawOldKey, rawNewKey);
return null;
}
}, true);
}
//如果没有就重命名
//Absent 缺席的,不在场的; 缺少的,缺乏的; 不在意的,茫然的;
public Boolean renameIfAbsent(K oldKey, K newKey) {
final byte[] rawOldKey = this.rawKey(oldKey);
final byte[] rawNewKey = this.rawKey(newKey);
return (Boolean)this.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) {
return connection.renameNX(rawOldKey, rawNewKey);
}
}, true);
}
//DataType类型的 类型
public DataType type(K key) {
final byte[] rawKey = this.rawKey(key);
return (DataType)this.execute(new RedisCallback<DataType>() {
public DataType doInRedis(RedisConnection connection) {
return connection.type(rawKey);
}
}, true);
}
public byte[] dump(K key) {
final byte[] rawKey = this.rawKey(key);
return (byte[])this.execute(new RedisCallback<byte[]>() {
public byte[] doInRedis(RedisConnection connection) {
return connection.dump(rawKey);
}
}, true);
}
//restore 修复; 归还; 交还; 使恢复;
public void restore(K key, final byte[] value, long timeToLive, TimeUnit unit) {
final byte[] rawKey = this.rawKey(key);
final long rawTimeout = TimeoutUtils.toMillis(timeToLive, unit);
this.execute(new RedisCallback<Object>() {
public Boolean doInRedis(RedisConnection connection) {
connection.restore(rawKey, rawTimeout, value);
return null;
}
}, true);
}
//multi 前缀
public void multi() {
this.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {
connection.multi();
return null;
}
}, true);
}
//discard 丢弃,抛弃; 解雇; 出牌;
public void discard() {
this.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {
connection.discard();
return null;
}
}, true);
}
//watch 注视,注意; 看守,监视; 守候(机会等); 密切注意
public void watch(K key) {
final byte[] rawKey = this.rawKey(key);
this.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) {
connection.watch(new byte[][]{rawKey});
return null;
}
}, true);
}
public void watch(Collection<K> keys) {
final byte[][] rawKeys = this.rawKeys(keys);
this.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) {
connection.watch(rawKeys);
return null;
}
}, true);
}
public void unwatch() {
this.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {
connection.unwatch();
return null;
}
}, true);
}
//sort 排序
public List<V> sort(SortQuery<K> query) {
return this.sort(query, this.valueSerializer);
}
public <T> List<T> sort(SortQuery<K> query, RedisSerializer<T> resultSerializer) {
final byte[] rawKey = this.rawKey(query.getKey());
final SortParameters params = QueryUtils.convertQuery(query, this.stringSerializer);
List<byte[]> vals = (List)this.execute(new RedisCallback<List<byte[]>>() {
public List<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
return connection.sort(rawKey, params);
}
}, true);
return SerializationUtils.deserialize(vals, resultSerializer);
}
public <T> List<T> sort(SortQuery<K> query, BulkMapper<T, V> bulkMapper) {
return this.sort(query, bulkMapper, this.valueSerializer);
}
public <T, S> List<T> sort(SortQuery<K> query, BulkMapper<T, S> bulkMapper, RedisSerializer<S> resultSerializer) {
List<S> values = this.sort(query, resultSerializer);
if (values != null && !values.isEmpty()) {
int bulkSize = query.getGetPattern().size();
List<T> result = new ArrayList(values.size() / bulkSize + 1);
List<S> bulk = new ArrayList(bulkSize);
Iterator var8 = values.iterator();
while(var8.hasNext()) {
S s = var8.next();
bulk.add(s);
if (bulk.size() == bulkSize) {
result.add(bulkMapper.mapBulk(Collections.unmodifiableList(bulk)));
bulk = new ArrayList(bulkSize);
}
}
return result;
} else {
return Collections.emptyList();
}
}
public Long sort(SortQuery<K> query, K storeKey) {
final byte[] rawStoreKey = this.rawKey(storeKey);
final byte[] rawKey = this.rawKey(query.getKey());
final SortParameters params = QueryUtils.convertQuery(query, this.stringSerializer);
return (Long)this.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.sort(rawKey, params, rawStoreKey);
}
}, true);
}
//BoundValueOperations暂时不知道什么意思,可能是操作边界值
//bound n界限,限制; 跃起; (球等的) 反跳 ,v缚; 给…划界,限制; 使弹回,使跳跃;
public BoundValueOperations<K, V> boundValueOps(K key) {
return new DefaultBoundValueOperations(key, this);
}
//操作值,描述具有简单值的条目
public ValueOperations<K, V> opsForValue() {
if (this.valueOps == null) {
this.valueOps = new DefaultValueOperations(this);
}
return this.valueOps;
}
//操作集合,操作具有list值的条目
public ListOperations<K, V> opsForList() {
if (this.listOps == null) {
this.listOps = new DefaultListOperations(this);
}
return this.listOps;
}
//以绑定指定key的方式,操作具有list的条目
public BoundListOperations<K, V> boundListOps(K key) {
return new DefaultBoundListOperations(key, this);
}
//以绑定指定key的方式,操作具有set的条目
public BoundSetOperations<K, V> boundSetOps(K key) {
return new DefaultBoundSetOperations(key, this);
}
//操作具有set值的条目
public SetOperations<K, V> opsForSet() {
if (this.setOps == null) {
this.setOps = new DefaultSetOperations(this);
}
return this.setOps;
}
//以绑定指定key的方式,操作具有ZSet(排序的set)的条目
public BoundZSetOperations<K, V> boundZSetOps(K key) {
return new DefaultBoundZSetOperations(key, this);
}
//操作具有ZSet值(排序的set)的条目
public ZSetOperations<K, V> opsForZSet() {
if (this.zSetOps == null) {
this.zSetOps = new DefaultZSetOperations(this);
}
return this.zSetOps;
}
//Geospatial 键操作
public GeoOperations<K, V> opsForGeo() {
if (this.geoOps == null) {
this.geoOps = new DefaultGeoOperations(this);
}
return this.geoOps;
}
//Redis Geospatial 键绑定操作
public BoundGeoOperations<K, V> boundGeoOps(K key) {
return new DefaultBoundGeoOperations(key, this);
}
//操作Redis HyperLogLog类型数据,比如:pfadd,pfcount,...
public HyperLogLogOperations<K, V> opsForHyperLogLog() {
if (this.hllOps == null) {
this.hllOps = new DefaultHyperLogLogOperations(this);
}
return this.hllOps;
}
//Redis Hash键绑定操作
public <HK, HV> BoundHashOperations<K, HK, HV> boundHashOps(K key) {
return new DefaultBoundHashOperations(key, this);
}
//操作Redis Hash类型数据
public <HK, HV> HashOperations<K, HK, HV> opsForHash() {
return new DefaultHashOperations(this);
}
//Cluster 群操作
public ClusterOperations<K, V> opsForCluster() {
return new DefaultClusterOperations(this);
}
public void killClient(final String host, final int port) {
this.execute(new RedisCallback<Void>() {
public Void doInRedis(RedisConnection connection) throws DataAccessException {
connection.killClient(host, port);
return null;
}
});
}
//获取redis客户端的集合
public List<RedisClientInfo> getClientList() {
return (List)this.execute(new RedisCallback<List<RedisClientInfo>>() {
public List<RedisClientInfo> doInRedis(RedisConnection connection) throws DataAccessException {
return connection.getClientList();
}
});
}
//SLAVEOF 命令用于在 Redis 运行时动态地修改复制(replication)功能的行为
public void slaveOf(final String host, final int port) {
this.execute(new RedisCallback<Void>() {
public Void doInRedis(RedisConnection connection) throws DataAccessException {
connection.slaveOf(host, port);
return null;
}
});
}
public void slaveOfNoOne() {
this.execute(new RedisCallback<Void>() {
public Void doInRedis(RedisConnection connection) throws DataAccessException {
connection.slaveOfNoOne();
return null;
}
});
}
public void setEnableTransactionSupport(boolean enableTransactionSupport) {
this.enableTransactionSupport = enableTransactionSupport;
}
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
}
1. 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
2. 针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
ValueOperations:简单K-V操作
SetOperations:set类型数据操作
ZSetOperations:zset类型数据操作
HashOperations:针对map类型的数据操作
ListOperations:针对list类型的数据操作
3. 提供了对key的“bound”(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key,即BoundKeyOperations:
BoundValueOperations
BoundSetOperations
BoundListOperations
BoundSetOperations
BoundHashOperations
4. 将事务操作封装,有容器控制。
5. 针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)
JdkSerializationRedisSerializer:POJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。是目前最常用的序列化策略。
StringRedisSerializer:Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。
JacksonJsonRedisSerializer:jackson-json工具提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。【需要jackson-mapper-asl工具支持】
OxmSerializer:提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。【需要spring-oxm模块的支持】
key的存活时间:
无论什么时候,只要有可能就利用key超时的优势。一个很好的例子就是储存一些诸如临时认证key之类的东西。当你去查找一个授权key时——以OAUTH为例——通常会得到一个超时时间。
这样在设置key的时候,设成同样的超时时间,Redis就会自动为你清除。
关系型数据库的redis
1: 把表名转换为key前缀 如, tag:
2: 第2段放置用于区分区key的字段--对应mysql中的主键的列名,如userid
3: 第3段放置主键值,如2,3,4...., a , b ,c
4: 第4段,写要存储的列名
例:user:userid:9:username
Redis的数据类型
String字符串
string是redis最基本的类型,一个key对应一个value。
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
string类型是Redis最基本的数据类型,一个键最大能存储512MB。
String类型的操作参考
链表
redis列表是简单的字符串列表,排序为插入的顺序。列表的最大长度为2^32-1。
redis的列表是使用链表实现的,这意味着,即使列表中有上百万个元素,增加一个元素到列表的头部或尾部的操作都是在常量的时间完成。
可以用列表获取最新的内容(像帖子,微博等),用ltrim很容易就会获取最新的内容,并移除旧的内容。
用列表可以实现生产者消费者模式,生产者调用lpush添加项到列表中,消费者调用rpop从列表中提取,如果没有元素,则轮询去获取,或者使用brpop等待生产者添加项到列表中。
List类型的操作参考
集合
redis集合是无序的字符串集合,集合中的值是唯一的,无序的。可以对集合执行很多操作,例如,测试元素是否存在,对多个集合执行交集、并集和差集等等。
我们通常可以用集合存储一些无关顺序的,表达对象间关系的数据,例如用户的角色,可以用sismember很容易就判断用户是否拥有某个角色。
在一些用到随机值的场合是非常适合的,可以用 srandmember/spop 获取/弹出一个随机元素。
同时,使用@EnableCaching开启声明式缓存支持,这样就可以使用基于注解的缓存技术。注解缓存是一个对缓存使用的抽象,通过在代码中添加下面的一些注解,达到缓存的效果。
Set类型的操作参考
ZSet 有序集合
有序集合由唯一的,不重复的字符串元素组成。有序集合中的每个元素都关联了一个浮点值,称为分数。可以把有序看成hash和集合的混合体,分数即为hash的key。
有序集合中的元素是按序存储的,不是请求时才排序的。
ZSet类型的操作类型
Hash-哈希
redis的哈希值是字符串字段和字符串之间的映射,是表示对象的完美数据类型。
哈希中的字段数量没有限制,所以可以在你的应用程序以不同的方式来使用哈希。
Hash类型的操作参考
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<!-- spring boot 配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
package com.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author janti
* reids 相关bean的配置
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 选择redis作为默认缓存工具
* @param redisTemplate
* @return
*/
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
return rcm;
}
/**
* retemplate相关配置
* @param factory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 值采用json序列化
template.setValueSerializer(jacksonSeial);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
// 设置hash key 和value序列化模式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();
return template;
}
/**
* 对hash类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}
/**
* 对redis字符串类型数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForValue();
}
/**
* 对链表类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
/**
* 对无序集合类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
/**
* 对有序集合类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}
-
spring-redis中使用了RedisTemplate来进行redis的操作,通过泛型的K和V设置键值对的对象类型。这里使用了string作为key的对象类型,值为Object。
-
对于Object,spring-redis默认使用了jdk自带的序列化,不推荐使用默认了。所以使用了json的序列化方式
- 对spring-redis对redis的五种数据类型也有支持
- HashOperations:对hash类型的数据操作
- ValueOperations:对redis字符串类型数据操作
- ListOperations:对链表类型的数据操作
- SetOperations:对无序集合类型的数据操作
-
ZSetOperations:对有序集合类型的数据操作
package com.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Component
public class RedisService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 默认过期时长,单位:秒
*/
public static final long DEFAULT_EXPIRE = 60 * 60 * 24;
/**
* 不设置过期时长
*/
public static final long NOT_EXPIRE = -1;
public boolean existsKey(String key) {
return redisTemplate.hasKey(key);
}
/**
* 重名名key,如果newKey已经存在,则newKey的原值被覆盖
*
* @param oldKey
* @param newKey
*/
public void renameKey(String oldKey, String newKey) {
redisTemplate.rename(oldKey, newKey);
}
/**
* newKey不存在时才重命名
*
* @param oldKey
* @param newKey
* @return 修改成功返回true
*/
public boolean renameKeyNotExist(String oldKey, String newKey) {
return redisTemplate.renameIfAbsent(oldKey, newKey);
}
/**
* 删除key
*
* @param key
*/
public void deleteKey(String key) {
redisTemplate.delete(key);
}
/**
* 删除多个key
*
* @param keys
*/
public void deleteKey(String... keys) {
Set<String> kSet = Stream.of(keys).map(k -> k).collect(Collectors.toSet());
redisTemplate.delete(kSet);
}
/**
* 删除Key的集合
*
* @param keys
*/
public void deleteKey(Collection<String> keys) {
Set<String> kSet = keys.stream().map(k -> k).collect(Collectors.toSet());
redisTemplate.delete(kSet);
}
/**
* 设置key的生命周期
*
* @param key
* @param time
* @param timeUnit
*/
public void expireKey(String key, long time, TimeUnit timeUnit) {
redisTemplate.expire(key, time, timeUnit);
}
/**
* 指定key在指定的日期过期
*
* @param key
* @param date
*/
public void expireKeyAt(String key, Date date) {
redisTemplate.expireAt(key, date);
}
/**
* 查询key的生命周期
*
* @param key
* @param timeUnit
* @return
*/
public long getKeyExpire(String key, TimeUnit timeUnit) {
return redisTemplate.getExpire(key, timeUnit);
}
/**
* 将key设置为永久有效
*
* @param key
*/
public void persistKey(String key) {
redisTemplate.persist(key);
}
}
package com.util;
/**
* redisKey设计
*/
public class RedisKeyUtil {
/**
* redis的key
* 形式为:
* 表名:主键名:主键值:列名
*
* @param tableName 表名
* @param majorKey 主键名
* @param majorKeyValue 主键值
* @param column 列名
* @return
*/
public static String getKeyWithColumn(String tableName,String majorKey,String majorKeyValue,String column){
StringBuffer buffer = new StringBuffer();
buffer.append(tableName).append(":");
buffer.append(majorKey).append(":");
buffer.append(majorKeyValue).append(":");
buffer.append(column);
return buffer.toString();
}
/**
* redis的key
* 形式为:
* 表名:主键名:主键值
*
* @param tableName 表名
* @param majorKey 主键名
* @param majorKeyValue 主键值
* @return
*/
public static String getKey(String tableName,String majorKey,String majorKeyValue){
StringBuffer buffer = new StringBuffer();
buffer.append(tableName).append(":");
buffer.append(majorKey).append(":");
buffer.append(majorKeyValue).append(":");
return buffer.toString();
}
}