知识点_20190314

#### 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();
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值