Redis深入实践(三)构建redis服务使用RedisTemplate

RedisTemplate是操作redis的一个API:先看下RedisTemplate的原码:具体的方法使看原码中的注释

RedisTemplate

帮助程序类,用于简化redis数据访问代码。

在给定对象和redis存储中的基础二进制数据之间执行自动序列化/反序列化。默认情况下,它使用对象的Java序列化(通过JDKSerialIdaseReDeSerialZER)。对于字符串密集型操作,请考虑使用专用的StringRedisTemplate.

中心方法是执行execute(),支持redis访问代码实现redisallback接口。它提供了redis connection处理,这样,无论是redisallback实现还是调用代码都不需要显式地关心检索/关闭redis连接,或者处理连接生命周期异常。对于典型的单步动作,有各种方便的方法。

一旦配置,这个类就是线程安全的。

请注意,虽然模板是通用的,但要正确地将给定对象转换为二进制数据或从二进制数据转换为给定对象,则取决于序列化程序/反序列化程序。

文章中的最主要的方法如下:


     在Redis连接中执行给定的操作。只要可能,操作对象引发的应用程序异常就会传播到调用方(只能取消选中)。Redis异常被转换为适当的DAO异常。允许返回结果对象,即域对象或域对象集合。对适合于redis存储的二进制数据的给定对象执行自动序列化/反序列化。注意:回调代码不应该处理事务本身!使用适当的事务管理器。通常,回调代码不能接触任何连接生命周期方法,比如close,以让模板完成其工作。
    public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {}
    

执行一个事务,使用默认的redisserializer来反序列化任何属于byte[]s或byte[]s或元组的集合或映射的结果。其他结果类型(long、boolean等)与转换后的结果相同。如果在RedisonConnectionFactory中禁用了Tx结果的转换,则将返回exec的结果,而不进行反序列化。此检查主要是为了与1.0向后兼容。

    public List<Object> exec() {}
执行事务,使用提供的redisserializer反序列化任何字节为[]s的结果或字节为[]s的集合。如果结果是映射,则提供的redisserializer将用于键和值。其他结果类型(long、boolean等)与转换后的结果相同。元组结果将自动转换为typedtuples。
    public List<Object> exec(RedisSerializer<?> valueSerializer) { }
       

删除
    public Boolean delete(K key) {}

删除集合中的key
    public Long delete(Collection<K> keys) { }
确定给定的键是否存在。
    public Boolean hasKey(K key) {  }
为给定的密钥设置生存时间。
    public Boolean expire(K key, final long timeout, final TimeUnit unit) {  }

为给定的密钥设置生存时间。
    public Boolean expireAt(K key, final Date date) {}

将给定消息发布到给定通道。
    public void convertAndSend(String channel, Object message) {  }

以秒为单位获得钥匙的生存时间。
    public Long getExpire(K key) {  }

 获取生存时间并将其转换为给定的时间单位。
    public Long getExpire(K key, final TimeUnit timeUnit) { }

 查找与给定模式匹配的所有键。
    public Set<K> keys(K pattern) { }

从给定的密钥中删除过期。
    public Boolean persist(K key) {}

将给定的键移动到具有索引的数据库。
    public Boolean move(K key, final int dbIndex) { }

从键空间返回随机键。
    public K randomKey() {}

重命名key
    public void rename(K oldKey, K newKey) { }

仅当newkey不存在时,才将key olename重命名为newkey。
    public Boolean renameIfAbsent(K oldKey, K newKey) {}

确定存储在键处的类型。
    public DataType type(K key) { }


执行redis dump命令并返回结果。redis使用非标准的序列化机制并包含校验和信息,因此返回原始字节,而不是使用valueserializer进行反序列化。使用dump的返回值作为要还原的值参数
    public byte[] dump(K key) { }

执行redis还原命令。传入的值应该是从dump(object)返回的准确序列化数据,因为redis使用非标准序列化机制。
    public void restore(K key, final byte[] value, long timeToLive, TimeUnit unit) {}
 标记事务块的开始命令将排队,然后可以通过调用redisperations.exec()或使用redisperations.discard()回滚来执行。
   public void multi() { }

放弃在redisperations.multi()之后发出的所有命令。
    public void discard() { }

在用redisperations.multi()启动的事务期间,观察给定的键是否有修改。
    public void watch(K key) { }

刷新所有以前的重读操作。观察(对象)键。
 

    public void unwatch() { }

排序:

为查询对元素排序。
    public List<V> sort(SortQuery<K> query) {
        return sort(query, valueSerializer);
    }

关闭由客户端中给定的ip:port标识的给定客户端连接。
   

    public void killClient(final String host, final int port) {  }
请求有关已连接客户端的信息和统计信息。
    

    @Override
    public List<RedisClientInfo> getClientList() {
        return execute(RedisServerCommands::getClientList);
    }

将redis复制设置更改为新的主服务器。
    @Override
    public void slaveOf(final String host, final int port) {}

将服务器更改为主服务器。
    public void slaveOfNoOne() {  }

返回特定于群集的操作接口
    @Override
    public ClusterOperations<K, V> opsForCluster() {

返回特定于地理空间的操作接口。
   

    public GeoOperations<K, V> opsForGeo() { }

返回绑定到给定键的特定于地理空间的操作接口。
    public BoundGeoOperations<K, V> boundGeoOps(K key) {}

返回对哈希值执行的操作。
    public <HK, HV> HashOperations<K, HK, HV> opsForHash() { }

返回对list值执行的操作。
    public ListOperations<K, V> opsForList() {}

返回对绑定到给定键的列表值执行的操作。
    public BoundListOperations<K, V> boundListOps(K key) { }

返回对绑定到给定键的set值执行的操作。
    public BoundSetOperations<K, V> boundSetOps(K key) { }

返回对set值执行的操作。
    public SetOperations<K, V> opsForSet() { }

返回对zSet值执行的操作。
    public BoundZSetOperations<K, V> boundZSetOps(K key) {}

/*
 * Copyright 2011-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
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.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.InvalidDataAccessApiUsageException;
import org.springframework.data.redis.RedisSystemException;
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.RedisKeyCommands;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.connection.RedisTxCommands;
import org.springframework.data.redis.connection.RedisZSetCommands.Tuple;
import org.springframework.data.redis.connection.SortParameters;
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.lang.Nullable;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;

/**
 * Helper class that simplifies Redis data access code.
 * <p/>
 * Performs automatic serialization/deserialization between the given objects and the underlying binary data in the
 * Redis store. By default, it uses Java serialization for its objects (through {@link JdkSerializationRedisSerializer}
 * ). For String intensive operations consider the dedicated {@link StringRedisTemplate}.
 * <p/>
 * The central method is execute, supporting Redis access code implementing the {@link RedisCallback} interface. It
 * provides {@link RedisConnection} handling such that neither the {@link RedisCallback} implementation nor the calling
 * code needs to explicitly care about retrieving/closing Redis connections, or handling Connection lifecycle
 * exceptions. For typical single step actions, there are various convenience methods.
 * <p/>
 * Once configured, this class is thread-safe.
 * <p/>
 * Note that while the template is generified, it is up to the serializers/deserializers to properly convert the given
 * Objects to and from binary data.
 * <p/>
 * <b>This is the central class in Redis support</b>.
 *
 * @author Costin Leau
 * @author Christoph Strobl
 * @author Ninad Divadkar
 * @author Anqing Shao
 * @author Mark Paluch
 * @param <K> the Redis key type against which the template works (usually a String)
 * @param <V> the Redis value type against which the template works
 * @see StringRedisTemplate
 */
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 @Nullable RedisSerializer<?> defaultSerializer;
	private @Nullable ClassLoader classLoader;

	@SuppressWarnings("rawtypes") private @Nullable RedisSerializer keySerializer = null;
	@SuppressWarnings("rawtypes") private @Nullable RedisSerializer valueSerializer = null;
	@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashKeySerializer = null;
	@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashValueSerializer = null;
	private RedisSerializer<String> stringSerializer = new StringRedisSerializer();

	private @Nullable ScriptExecutor<K> scriptExecutor;

	// cache singleton objects (where possible)
	private @Nullable ValueOperations<K, V> valueOps;
	private @Nullable ListOperations<K, V> listOps;
	private @Nullable SetOperations<K, V> setOps;
	private @Nullable ZSetOperations<K, V> zSetOps;
	private @Nullable GeoOperations<K, V> geoOps;
	private @Nullable HyperLogLogOperations<K, V> hllOps;

	/**
	 * Constructs a new <code>RedisTemplate</code> instance.
	 */
	public RedisTemplate() {}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisAccessor#afterPropertiesSet()
	 */
	@Override
	public void afterPropertiesSet() {

		super.afterPropertiesSet();

		boolean defaultUsed = false;

		if (defaultSerializer == null) {

			defaultSerializer = new JdkSerializationRedisSerializer(
					classLoader != null ? classLoader : this.getClass().getClassLoader());
		}

		if (enableDefaultSerializer) {

			if (keySerializer == null) {
				keySerializer = defaultSerializer;
				defaultUsed = true;
			}
			if (valueSerializer == null) {
				valueSerializer = defaultSerializer;
				defaultUsed = true;
			}
			if (hashKeySerializer == null) {
				hashKeySerializer = defaultSerializer;
				defaultUsed = true;
			}
			if (hashValueSerializer == null) {
				hashValueSerializer = defaultSerializer;
				defaultUsed = true;
			}
		}

		if (enableDefaultSerializer && defaultUsed) {
			Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");
		}

		if (scriptExecutor == null) {
			this.scriptExecutor = new DefaultScriptExecutor<>(this);
		}

		initialized = true;
	}

	/*
	 * (non-Javadoc)

	 * @see org.springframework.data.redis.core.RedisOperations#execute(org.springframework.data.redis.core.RedisCallback)
	 */
	@Override
	@Nullable
	public <T> T execute(RedisCallback<T> action) {
		return execute(action, isExposeConnection());
	}

	/**
	 * Executes the given action object within a connection, which can be exposed or not.
	 *
	 * @param <T> return type
	 * @param action callback object that specifies the Redis action
	 * @param exposeConnection whether to enforce exposure of the native Redis Connection to callback code
	 * @return object returned by the action
	 */
	@Nullable
	public <T> T execute(RedisCallback<T> action, boolean exposeConnection) {
		return execute(action, exposeConnection, false);
	}

	/**
	 * Executes the given action object within a connection that can be exposed or not. Additionally, the connection can
	 * be pipelined. Note the results of the pipeline are discarded (making it suitable for write-only scenarios).
	 *在Redis连接中执行给定的操作。只要可能,操作对象引发的应用程序异常就会传播到调用方(只能取消选中)。Redis异常被转换为适当的DAO异常。允许返回结果对象,即域对象或域对象集合。对适合于redis存储的二进制数据的给定对象执行自动序列化/反序列化。注意:回调代码不应该处理事务本身!使用适当的事务管理器。通常,回调代码不能接触任何连接生命周期方法,比如close,以让模板完成其工作。
	 * @param <T> return type
	 * @param action callback object to execute
	 * @param exposeConnection whether to enforce exposure of the native Redis Connection to callback code
	 * @param pipeline whether to pipeline or not the connection for the execution
	 * @return object returned by the action
	 */
	@Nullable
	public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {

		Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
		Assert.notNull(action, "Callback object must not be null");

		RedisConnectionFactory factory = getRequiredConnectionFactory();
		RedisConnection conn = null;
		try {

			if (enableTransactionSupport) {
				// only bind resources in case of potential transaction synchronization
				conn = RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);
			} else {
				conn = RedisConnectionUtils.getConnection(factory);
			}

			boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);

			RedisConnection connToUse = preProcessConnection(conn, existingConnection);

			boolean pipelineStatus = connToUse.isPipelined();
			if (pipeline && !pipelineStatus) {
				connToUse.openPipeline();
			}

			RedisConnection connToExpose = (exposeConnection ? connToUse : createRedisConnectionProxy(connToUse));
			T result = action.doInRedis(connToExpose);

			// close pipeline
			if (pipeline && !pipelineStatus) {
				connToUse.closePipeline();
			}

			// TODO: any other connection processing?
			return postProcessResult(result, connToUse, existingConnection);
		} finally {
			RedisConnectionUtils.releaseConnection(conn, factory);
		}
	}

	/*
	 * (non-Javadoc)
执行redis会话。允许在同一会话中执行多个操作,通过redisperations.multi()和redisperations.watch(collection)操作启用“事务”功能。
	 * @see org.springframework.data.redis.core.RedisOperations#execute(org.springframework.data.redis.core.SessionCallback)
	 */
	@Override
	public <T> T execute(SessionCallback<T> session) {

		Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
		Assert.notNull(session, "Callback object must not be null");

		RedisConnectionFactory factory = getRequiredConnectionFactory();
		// bind connection
		RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);
		try {
			return session.execute(this);
		} finally {
			RedisConnectionUtils.unbindConnection(factory);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#executePipelined(org.springframework.data.redis.core.SessionCallback)
在管道连接上执行给定的redis会话。允许对事务进行流水线处理。请注意,回调不能返回非空值,因为它会被管道覆盖。
	 */
	@Override
	public List<Object> executePipelined(SessionCallback<?> session) {
		return executePipelined(session, valueSerializer);
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#executePipelined(org.springframework.data.redis.core.SessionCallback, org.springframework.data.redis.serializer.RedisSerializer)
在管道连接上执行给定的redis会话。允许对事务进行流水线处理。请注意,回调不能返回非空值,因为它会被管道覆盖。
	 */
	@Override
	public List<Object> executePipelined(SessionCallback<?> session, @Nullable RedisSerializer<?> resultSerializer) {

		Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
		Assert.notNull(session, "Callback object must not be null");

		RedisConnectionFactory factory = getRequiredConnectionFactory();
		// bind connection
		RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);
		try {
			return execute((RedisCallback<List<Object>>) connection -> {
				connection.openPipeline();
				boolean pipelinedClosed = false;
				try {
					Object result = 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;
					return deserializeMixedResults(closePipeline, resultSerializer, hashKeySerializer, hashValueSerializer);
				} finally {
					if (!pipelinedClosed) {
						connection.closePipeline();
					}
				}
			});
		} finally {
			RedisConnectionUtils.unbindConnection(factory);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#executePipelined(org.springframework.data.redis.core.RedisCallback)
	 */
	@Override
	public List<Object> executePipelined(RedisCallback<?> action) {
		return executePipelined(action, valueSerializer);
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#executePipelined(org.springframework.data.redis.core.RedisCallback, org.springframework.data.redis.serializer.RedisSerializer)
在管道连接上执行给定的redis会话,使用专用序列化程序返回结果。允许对事务进行流水线处理。请注意,回调不能返回非空值,因为它会被管道覆盖。
	 */
	@Override
	public List<Object> executePipelined(RedisCallback<?> action, @Nullable RedisSerializer<?> resultSerializer) {

		return execute((RedisCallback<List<Object>>) connection -> {
			connection.openPipeline();
			boolean pipelinedClosed = false;
			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;
				return deserializeMixedResults(closePipeline, resultSerializer, hashKeySerializer, hashValueSerializer);
			} finally {
				if (!pipelinedClosed) {
					connection.closePipeline();
				}
			}
		});
	}

	/*
	 * (non-Javadoc)
        执行给定的RedisScript,。
	 * @see org.springframework.data.redis.core.RedisOperations#execute(org.springframework.data.redis.core.script.RedisScript, java.util.List, java.lang.Object[])
	 */
	@Override
	public <T> T execute(RedisScript<T> script, List<K> keys, Object... args) {
		return scriptExecutor.execute(script, keys, args);
	}

	/*
	 * (non-Javadoc)
        使用提供的RedisSerializers序列化脚本参数和结果
	 * @see org.springframework.data.redis.core.RedisOperations#execute(org.springframework.data.redis.core.script.RedisScript, org.springframework.data.redis.serializer.RedisSerializer, org.springframework.data.redis.serializer.RedisSerializer, java.util.List, java.lang.Object[])
	 */
	@Override
	public <T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSerializer<T> resultSerializer,
			List<K> keys, Object... args) {
		return scriptExecutor.execute(script, argsSerializer, resultSerializer, keys, args);
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#executeWithStickyConnection(org.springframework.data.redis.core.RedisCallback)
	 */
	@Override
	public <T extends Closeable> T executeWithStickyConnection(RedisCallback<T> callback) {

		Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
		Assert.notNull(callback, "Callback object must not be null");

		RedisConnectionFactory factory = getRequiredConnectionFactory();

		RedisConnection connection = preProcessConnection(RedisConnectionUtils.doGetConnection(factory, true, false, false),
				false);

		return callback.doInRedis(connection);
	}

	private Object executeSession(SessionCallback<?> session) {
		return session.execute(this);
	}

	protected RedisConnection createRedisConnectionProxy(RedisConnection pm) {
		Class<?>[] ifcs = ClassUtils.getAllInterfacesForClass(pm.getClass(), getClass().getClassLoader());
		return (RedisConnection) Proxy.newProxyInstance(pm.getClass().getClassLoader(), ifcs,
				new CloseSuppressingInvocationHandler(pm));
	}

	/**
	 * Processes the connection (before any settings are executed on it). Default implementation returns the connection as
	 * is.
	 *
	 * @param connection redis connection
	 */
	protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
		return connection;
	}

	@Nullable
	protected <T> T postProcessResult(@Nullable T result, RedisConnection conn, boolean existingConnection) {
		return result;
	}

	/**
	 * Returns whether to expose the native Redis connection to RedisCallback code, or rather a connection proxy (the
	 * default).
	 *
	 * @return whether to expose the native Redis connection or not
	 */
	public boolean isExposeConnection() {
		return exposeConnection;
	}

	/**
	 * Sets whether to expose the Redis connection to {@link RedisCallback} code. Default is "false": a proxy will be
	 * returned, suppressing <tt>quit</tt> and <tt>disconnect</tt> calls.
	 *
	 * @param exposeConnection
	 */
	public void setExposeConnection(boolean exposeConnection) {
		this.exposeConnection = exposeConnection;
	}

	/**
	 * @return Whether or not the default serializer should be used. If not, any serializers not explicitly set will
	 *         remain null and values will not be serialized or deserialized.
	 */
	public boolean isEnableDefaultSerializer() {
		return enableDefaultSerializer;
	}

	/**
	 * @param enableDefaultSerializer Whether or not the default serializer should be used. If not, any serializers not
	 *          explicitly set will remain null and values will not be serialized or deserialized.
	 */
	public void setEnableDefaultSerializer(boolean enableDefaultSerializer) {
		this.enableDefaultSerializer = enableDefaultSerializer;
	}

	/**
	 * Returns the default serializer used by this template.
	 *
	 * @return template default serializer
	 */
	@Nullable
	public RedisSerializer<?> getDefaultSerializer() {
		return defaultSerializer;
	}

	/**
	 * Sets the default serializer to use for this template. All serializers (expect the
	 * {@link #setStringSerializer(RedisSerializer)}) are initialized to this value unless explicitly set. Defaults to
	 * {@link JdkSerializationRedisSerializer}.
	 *
	 * @param serializer default serializer to use
	 */
	public void setDefaultSerializer(RedisSerializer<?> serializer) {
		this.defaultSerializer = serializer;
	}

	/**
	 * Sets the key serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
	 *
	 * @param serializer the key serializer to be used by this template.
	 */
	public void setKeySerializer(RedisSerializer<?> serializer) {
		this.keySerializer = serializer;
	}

	/**
	 * Returns the key serializer used by this template.
	 *
	 * @return the key serializer used by this template.
	 */
	@Override
	public RedisSerializer<?> getKeySerializer() {
		return keySerializer;
	}

	/**
	 * Sets the value serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
	 *
	 * @param serializer the value serializer to be used by this template.
	 */
	public void setValueSerializer(RedisSerializer<?> serializer) {
		this.valueSerializer = serializer;
	}

	/**
	 * Returns the value serializer used by this template.
	 *
	 * @return the value serializer used by this template.
	 */
	@Override
	public RedisSerializer<?> getValueSerializer() {
		return valueSerializer;
	}

	/**
	 * Returns the hashKeySerializer.
	 *
	 * @return Returns the hashKeySerializer
	 */
	@Override
	public RedisSerializer<?> getHashKeySerializer() {
		return hashKeySerializer;
	}

	/**
	 * Sets the hash key (or field) serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
	 *
	 * @param hashKeySerializer The hashKeySerializer to set.
	 */
	public void setHashKeySerializer(RedisSerializer<?> hashKeySerializer) {
		this.hashKeySerializer = hashKeySerializer;
	}

	/**
	 * Returns the hashValueSerializer.
	 *
	 * @return Returns the hashValueSerializer
	 */
	@Override
	public RedisSerializer<?> getHashValueSerializer() {
		return hashValueSerializer;
	}

	/**
	 * Sets the hash value serializer to be used by this template. Defaults to {@link #getDefaultSerializer()}.
	 *
	 * @param hashValueSerializer The hashValueSerializer to set.
	 */
	public void setHashValueSerializer(RedisSerializer<?> hashValueSerializer) {
		this.hashValueSerializer = hashValueSerializer;
	}

	/**
	 * Returns the stringSerializer.
	 *
	 * @return Returns the stringSerializer
	 */
	public RedisSerializer<String> getStringSerializer() {
		return stringSerializer;
	}

	/**
	 * Sets the string value serializer to be used by this template (when the arguments or return types are always
	 * strings). Defaults to {@link StringRedisSerializer}.
	 *
	 * @see ValueOperations#get(Object, long, long)
	 * @param stringSerializer The stringValueSerializer to set.
	 */
	public void setStringSerializer(RedisSerializer<String> stringSerializer) {
		this.stringSerializer = stringSerializer;
	}

	/**
	 * @param scriptExecutor The {@link ScriptExecutor} to use for executing Redis scripts
	 */
	public void setScriptExecutor(ScriptExecutor<K> scriptExecutor) {
		this.scriptExecutor = scriptExecutor;
	}

	@SuppressWarnings("unchecked")
	private byte[] rawKey(Object key) {
		Assert.notNull(key, "non null key required");
		if (keySerializer == null && key instanceof byte[]) {
			return (byte[]) key;
		}
		return keySerializer.serialize(key);
	}

	private byte[] rawString(String key) {
		return stringSerializer.serialize(key);
	}

	@SuppressWarnings("unchecked")
	private byte[] rawValue(Object value) {
		if (valueSerializer == null && value instanceof byte[]) {
			return (byte[]) value;
		}
		return valueSerializer.serialize(value);
	}

	private byte[][] rawKeys(Collection<K> keys) {
		final byte[][] rawKeys = new byte[keys.size()][];

		int i = 0;
		for (K key : keys) {
			rawKeys[i++] = rawKey(key);
		}

		return rawKeys;
	}

	@SuppressWarnings("unchecked")
	private K deserializeKey(byte[] value) {
		return keySerializer != null ? (K) keySerializer.deserialize(value) : (K) value;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Nullable
	private List<Object> deserializeMixedResults(@Nullable List<Object> rawValues,
			@Nullable RedisSerializer valueSerializer, @Nullable RedisSerializer hashKeySerializer,
			@Nullable RedisSerializer hashValueSerializer) {

		if (rawValues == null) {
			return null;
		}

		List<Object> values = new ArrayList<>();
		for (Object rawValue : rawValues) {

			if (rawValue instanceof byte[] && valueSerializer != null) {
				values.add(valueSerializer.deserialize((byte[]) rawValue));
			} else if (rawValue instanceof List) {
				// Lists are the only potential Collections of mixed values....
				values.add(deserializeMixedResults((List) rawValue, valueSerializer, hashKeySerializer, hashValueSerializer));
			} else if (rawValue instanceof Set && !(((Set) rawValue).isEmpty())) {
				values.add(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;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private Set<?> deserializeSet(Set rawSet, @Nullable RedisSerializer valueSerializer) {

		if (rawSet.isEmpty()) {
			return rawSet;
		}

		Object setValue = rawSet.iterator().next();

		if (setValue instanceof byte[] && valueSerializer != null) {
			return (SerializationUtils.deserialize(rawSet, valueSerializer));
		} else if (setValue instanceof Tuple) {
			return convertTupleValues(rawSet, valueSerializer);
		} else {
			return rawSet;
		}
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Set<TypedTuple<V>> convertTupleValues(Set<Tuple> rawValues, @Nullable RedisSerializer valueSerializer) {

		Set<TypedTuple<V>> set = new LinkedHashSet<>(rawValues.size());
		for (Tuple rawValue : rawValues) {
			Object value = rawValue.getValue();
			if (valueSerializer != null) {
				value = valueSerializer.deserialize(rawValue.getValue());
			}
			set.add(new DefaultTypedTuple(value, rawValue.getScore()));
		}
		return set;
	}

	//
	// RedisOperations
	//

	/**
	执行一个事务,使用默认的redisserializer来反序列化任何属于byte[]s或byte[]s或元组的集合或映射的结果。其他结果类型(long、boolean等)与转换后的结果相同。如果在RedisonConnectionFactory中禁用了Tx结果的转换,则将返回exec的结果,而不进行反序列化。此检查主要是为了与1.0向后兼容。
	 *
	 * @return The (possibly deserialized) results of transaction exec
	 */
	@Override
	public List<Object> exec() {

		List<Object> results = execRaw();
		if (getRequiredConnectionFactory().getConvertPipelineAndTxResults()) {
			return deserializeMixedResults(results, valueSerializer, hashKeySerializer, hashValueSerializer);
		} else {
			return results;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#exec(org.springframework.data.redis.serializer.RedisSerializer)
执行事务,使用提供的redisserializer反序列化任何字节为[]s的结果或字节为[]s的集合。如果结果是映射,则提供的redisserializer将用于键和值。其他结果类型(long、boolean等)与转换后的结果相同。元组结果将自动转换为typedtuples。
	 */
	@Override
	public List<Object> exec(RedisSerializer<?> valueSerializer) {
		return deserializeMixedResults(execRaw(), valueSerializer, valueSerializer, valueSerializer);
	}

	protected List<Object> execRaw() {

		List<Object> raw = execute(RedisTxCommands::exec);
		return raw == null ? Collections.emptyList() : raw;
	}

	/*
        删除
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#delete(java.lang.Object)
	 */
	@Override
	public Boolean delete(K key) {

		byte[] rawKey = rawKey(key);

		Long result = execute(connection -> connection.del(rawKey), true);

		return result != null && result.intValue() == 1;
	}

	/*
	 * (non-Javadoc)
        删除集合中的key
	 * @see org.springframework.data.redis.core.RedisOperations#delete(java.util.Collection)
	 */
	@Override
	public Long delete(Collection<K> keys) {

		if (CollectionUtils.isEmpty(keys)) {
			return 0L;
		}

		byte[][] rawKeys = rawKeys(keys);

		return execute(connection -> connection.del(rawKeys), true);
	}

	/*
        确定给定的键是否存在。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#hasKey(java.lang.Object)
	 */
	@Override
	public Boolean hasKey(K key) {

		byte[] rawKey = rawKey(key);

		return execute(connection -> connection.exists(rawKey), true);
	}

	/*
        为给定的密钥设置生存时间。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#expire(java.lang.Object, long, java.util.concurrent.TimeUnit)
	 */
	@Override
	public Boolean expire(K key, final long timeout, final TimeUnit unit) {

		byte[] rawKey = rawKey(key);
		long rawTimeout = TimeoutUtils.toMillis(timeout, unit);

		return execute(connection -> {
			try {
				return connection.pExpire(rawKey, rawTimeout);
			} catch (Exception e) {
				// Driver may not support pExpire or we may be running on Redis 2.4
				return connection.expire(rawKey, TimeoutUtils.toSeconds(timeout, unit));
			}
		}, true);
	}

	/*为给定的密钥设置生存时间。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#expireAt(java.lang.Object, java.util.Date)
	 */
	@Override
	public Boolean expireAt(K key, final Date date) {

		byte[] rawKey = rawKey(key);

		return execute(connection -> {
			try {
				return connection.pExpireAt(rawKey, date.getTime());
			} catch (Exception e) {
				return connection.expireAt(rawKey, date.getTime() / 1000);
			}
		}, true);
	}

	/*将给定消息发布到给定通道。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#convertAndSend(java.lang.String, java.lang.Object)
	 */
	@Override
	public void convertAndSend(String channel, Object message) {

		Assert.hasText(channel, "a non-empty channel is required");

		byte[] rawChannel = rawString(channel);
		byte[] rawMessage = rawValue(message);

		execute(connection -> {
			connection.publish(rawChannel, rawMessage);
			return null;
		}, true);
	}

	//
	// Value operations
	//

	/*以秒为单位获得钥匙的生存时间。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#getExpire(java.lang.Object)
	 */
	@Override
	public Long getExpire(K key) {

		byte[] rawKey = rawKey(key);
		return execute(connection -> connection.ttl(rawKey), true);
	}

	/*获取生存时间并将其转换为给定的时间单位。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#getExpire(java.lang.Object, java.util.concurrent.TimeUnit)
	 */
	@Override
	public Long getExpire(K key, final TimeUnit timeUnit) {

		byte[] rawKey = rawKey(key);
		return execute(connection -> {
			try {
				return connection.pTtl(rawKey, timeUnit);
			} catch (Exception e) {
				// Driver may not support pTtl or we may be running on Redis 2.4
				return connection.ttl(rawKey, timeUnit);
			}
		}, true);
	}

	/*查找与给定模式匹配的所有键。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#keys(java.lang.Object)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Set<K> keys(K pattern) {

		byte[] rawKey = rawKey(pattern);
		Set<byte[]> rawKeys = execute(connection -> connection.keys(rawKey), true);

		return keySerializer != null ? SerializationUtils.deserialize(rawKeys, keySerializer) : (Set<K>) rawKeys;
	}

	/*从给定的密钥中删除过期。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#persist(java.lang.Object)
	 */
	@Override
	public Boolean persist(K key) {

		byte[] rawKey = rawKey(key);
		return execute(connection -> connection.persist(rawKey), true);
	}

	/*将给定的键移动到具有索引的数据库。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#move(java.lang.Object, int)
	 */
	@Override
	public Boolean move(K key, final int dbIndex) {

		byte[] rawKey = rawKey(key);
		return execute(connection -> connection.move(rawKey, dbIndex), true);
	}

	/*从键空间返回随机键。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#randomKey()
	 */
	@Override
	public K randomKey() {

		byte[] rawKey = execute(RedisKeyCommands::randomKey, true);
		return deserializeKey(rawKey);
	}

	/*重命名key
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#rename(java.lang.Object, java.lang.Object)
	 */
	@Override
	public void rename(K oldKey, K newKey) {

		byte[] rawOldKey = rawKey(oldKey);
		byte[] rawNewKey = rawKey(newKey);

		execute(connection -> {
			connection.rename(rawOldKey, rawNewKey);
			return null;
		}, true);
	}

	/*仅当newkey不存在时,才将key olename重命名为newkey。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#renameIfAbsent(java.lang.Object, java.lang.Object)
	 */
	@Override
	public Boolean renameIfAbsent(K oldKey, K newKey) {

		byte[] rawOldKey = rawKey(oldKey);
		byte[] rawNewKey = rawKey(newKey);
		return execute(connection -> connection.renameNX(rawOldKey, rawNewKey), true);
	}

	/*确定存储在键处的类型。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#type(java.lang.Object)
	 */
	@Override
	public DataType type(K key) {

		byte[] rawKey = rawKey(key);
		return execute(connection -> connection.type(rawKey), true);
	}

	/**
	 * Executes the Redis dump command and returns the results. Redis uses a non-standard serialization mechanism and
	 * includes checksum information, thus the raw bytes are returned as opposed to deserializing with valueSerializer.
	 * Use the return value of dump as the value argument to restore
	 *执行redis dump命令并返回结果。redis使用非标准的序列化机制并包含校验和信息,因此返回原始字节,而不是使用valueserializer进行反序列化。使用dump的返回值作为要还原的值参数
	 * @param key The key to dump
	 * @return results The results of the dump operation
	 */
	@Override
	public byte[] dump(K key) {

		byte[] rawKey = rawKey(key);
		return execute(connection -> connection.dump(rawKey), true);
	}

	/**
	 * Executes the Redis restore command. The value passed in should be the exact serialized data returned from
	 * {@link #dump(Object)}, since Redis uses a non-standard serialization mechanism.
	 *执行redis还原命令。传入的值应该是从dump(object)返回的准确序列化数据,因为redis使用非标准序列化机制。
	 * @param key The key to restore
	 * @param value The value to restore, as returned by {@link #dump(Object)}
	 * @param timeToLive An expiration for the restored key, or 0 for no expiration
	 * @param unit The time unit for timeToLive
	 * @throws RedisSystemException if the key you are attempting to restore already exists.
	 */
	@Override
	public void restore(K key, final byte[] value, long timeToLive, TimeUnit unit) {

		byte[] rawKey = rawKey(key);
		long rawTimeout = TimeoutUtils.toMillis(timeToLive, unit);

		execute(connection -> {
			connection.restore(rawKey, rawTimeout, value);
			return null;
		}, true);
	}

	/*
	 * (non-Javadoc)
        标记事务块的开始。

        命令将排队,然后可以通过调用redisperations.exec()或使用redisperations.discard()回滚来执行。
	 * @see org.springframework.data.redis.core.RedisOperations#multi()
	 */
	@Override
	public void multi() {
		execute(connection -> {
			connection.multi();
			return null;
		}, true);
	}

	/*放弃在redisperations.multi()之后发出的所有命令。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#discard()
	 */
	@Override
	public void discard() {

		execute(connection -> {
			connection.discard();
			return null;
		}, true);
	}

	/*在用redisperations.multi()启动的事务期间,观察给定的键是否有修改。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#watch(java.lang.Object)
	 */
	@Override
	public void watch(K key) {

		byte[] rawKey = rawKey(key);

		execute(connection -> {
			connection.watch(rawKey);
			return null;
		}, true);
	}

	/*在用redisperations.multi()启动的事务期间,观察给定的键是否有修改。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#watch(java.util.Collection)
	 */
	@Override
	public void watch(Collection<K> keys) {

		byte[][] rawKeys = rawKeys(keys);

		execute(connection -> {
			connection.watch(rawKeys);
			return null;
		}, true);
	}

	/*刷新所有以前的重读操作。观察(对象)键。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#unwatch()
	 */
	@Override
	public void unwatch() {

		execute(connection -> {
			connection.unwatch();
			return null;
		}, true);
	}

	// Sort operations

	/*为查询对元素排序。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#sort(org.springframework.data.redis.core.query.SortQuery)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<V> sort(SortQuery<K> query) {
		return sort(query, valueSerializer);
	}

	/*为查询对元素排序。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#sort(org.springframework.data.redis.core.query.SortQuery, org.springframework.data.redis.serializer.RedisSerializer)
	 */
	@Override
	public <T> List<T> sort(SortQuery<K> query, @Nullable RedisSerializer<T> resultSerializer) {

		byte[] rawKey = rawKey(query.getKey());
		SortParameters params = QueryUtils.convertQuery(query, stringSerializer);

		List<byte[]> vals = execute(connection -> connection.sort(rawKey, params), true);

		return SerializationUtils.deserialize(vals, resultSerializer);
	}

	/*为查询对元素排序。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#sort(org.springframework.data.redis.core.query.SortQuery, org.springframework.data.redis.core.BulkMapper)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public <T> List<T> sort(SortQuery<K> query, BulkMapper<T, V> bulkMapper) {
		return sort(query, bulkMapper, valueSerializer);
	}

	/*为查询对元素排序。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#sort(org.springframework.data.redis.core.query.SortQuery, org.springframework.data.redis.core.BulkMapper, org.springframework.data.redis.serializer.RedisSerializer)
	 */
	@Override
	public <T, S> List<T> sort(SortQuery<K> query, BulkMapper<T, S> bulkMapper,
			@Nullable RedisSerializer<S> resultSerializer) {

		List<S> values = sort(query, resultSerializer);

		if (values == null || values.isEmpty()) {
			return Collections.emptyList();
		}

		int bulkSize = query.getGetPattern().size();
		List<T> result = new ArrayList<>(values.size() / bulkSize + 1);

		List<S> bulk = new ArrayList<>(bulkSize);
		for (S s : values) {

			bulk.add(s);
			if (bulk.size() == bulkSize) {
				result.add(bulkMapper.mapBulk(Collections.unmodifiableList(bulk)));
				// create a new list (we could reuse the old one but the client might hang on to it for some reason)
				bulk = new ArrayList<>(bulkSize);
			}
		}

		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#sort(org.springframework.data.redis.core.query.SortQuery, java.lang.Object)
	 */
	@Override
	public Long sort(SortQuery<K> query, K storeKey) {

		byte[] rawStoreKey = rawKey(storeKey);
		byte[] rawKey = rawKey(query.getKey());
		SortParameters params = QueryUtils.convertQuery(query, stringSerializer);

		return execute(connection -> connection.sort(rawKey, params, rawStoreKey), true);
	}

	/*关闭由客户端中给定的ip:port标识的给定客户端连接。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#killClient(java.lang.Object)
	 */
	@Override
	public void killClient(final String host, final int port) {

		execute((RedisCallback<Void>) connection -> {
			connection.killClient(host, port);
			return null;
		});
	}
	/*请求有关已连接客户端的信息和统计信息。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#getClientList()
	 */
	@Override
	public List<RedisClientInfo> getClientList() {
		return execute(RedisServerCommands::getClientList);
	}

	/*将redis复制设置更改为新的主服务器。
	 * @see org.springframework.data.redis.core.RedisOperations#slaveOf(java.lang.String, int)
	 */
	@Override
	public void slaveOf(final String host, final int port) {

		execute((RedisCallback<Void>) connection -> {

			connection.slaveOf(host, port);
			return null;
		});
	}

	/*将服务器更改为主服务器。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#slaveOfNoOne()
	 */
	@Override
	public void slaveOfNoOne() {

		execute((RedisCallback<Void>) connection -> {
			connection.slaveOfNoOne();
			return null;
		});
	}

	/*返回特定于群集的操作接口。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#opsForCluster()
	 */
	@Override
	public ClusterOperations<K, V> opsForCluster() {
		return new DefaultClusterOperations<>(this);
	}

	/*返回特定于地理空间的操作接口。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#opsForGeo()
	 */
	@Override
	public GeoOperations<K, V> opsForGeo() {

		if (geoOps == null) {
			geoOps = new DefaultGeoOperations<>(this);
		}
		return geoOps;
	}

	/*返回绑定到给定键的特定于地理空间的操作接口。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#boundGeoOps(java.lang.Object)
	 */
	@Override
	public BoundGeoOperations<K, V> boundGeoOps(K key) {
		return new DefaultBoundGeoOperations<>(key, this);
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#boundHashOps(java.lang.Object)
	 */
	@Override
	public <HK, HV> BoundHashOperations<K, HK, HV> boundHashOps(K key) {
		return new DefaultBoundHashOperations<>(key, this);
	}

	/*返回对哈希值执行的操作。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#opsForHash()
	 */
	@Override
	public <HK, HV> HashOperations<K, HK, HV> opsForHash() {
		return new DefaultHashOperations<>(this);
	}

	/*
	 * 
	 * @see org.springframework.data.redis.core.RedisOperations#opsForHyperLogLog()
	 */
	@Override
	public HyperLogLogOperations<K, V> opsForHyperLogLog() {

		if (hllOps == null) {
			hllOps = new DefaultHyperLogLogOperations<>(this);
		}
		return hllOps;
	}

	/*返回对list值执行的操作。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#opsForList()
	 */
	@Override
	public ListOperations<K, V> opsForList() {

		if (listOps == null) {
			listOps = new DefaultListOperations<>(this);
		}
		return listOps;
	}

	/*返回对绑定到给定键的列表值执行的操作。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#boundListOps(java.lang.Object)
	 */
	@Override
	public BoundListOperations<K, V> boundListOps(K key) {
		return new DefaultBoundListOperations<>(key, this);
	}

	/*返回对绑定到给定键的set值执行的操作。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#boundSetOps(java.lang.Object)
	 */
	@Override
	public BoundSetOperations<K, V> boundSetOps(K key) {
		return new DefaultBoundSetOperations<>(key, this);
	}

	/*返回对set值执行的操作。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#opsForSet()
	 */
	@Override
	public SetOperations<K, V> opsForSet() {

		if (setOps == null) {
			setOps = new DefaultSetOperations<>(this);
		}
		return setOps;
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#boundValueOps(java.lang.Object)
	 */
	@Override
	public BoundValueOperations<K, V> boundValueOps(K key) {
		return new DefaultBoundValueOperations<>(key, this);
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#opsForValue()
	 */
	@Override
	public ValueOperations<K, V> opsForValue() {

		if (valueOps == null) {
			valueOps = new DefaultValueOperations<>(this);
		}
		return valueOps;
	}

	/*返回对zSet值执行的操作。
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#boundZSetOps(java.lang.Object)
	 */
	@Override
	public BoundZSetOperations<K, V> boundZSetOps(K key) {
		return new DefaultBoundZSetOperations<>(key, this);
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#opsForZSet()
	 */
	@Override
	public ZSetOperations<K, V> opsForZSet() {

		if (zSetOps == null) {
			zSetOps = new DefaultZSetOperations<>(this);
		}
		return zSetOps;
	}

	/**
	 * If set to {@code true} {@link RedisTemplate} will use {@literal MULTI...EXEC|DISCARD} to keep track of operations.
	 *
	 * @param enableTransactionSupport
	 * @since 1.3
	 */
	public void setEnableTransactionSupport(boolean enableTransactionSupport) {
		this.enableTransactionSupport = enableTransactionSupport;
	}

	/**
	 * Set the {@link ClassLoader} to be used for the default {@link JdkSerializationRedisSerializer} in case no other
	 * {@link RedisSerializer} is explicitly set as the default one.
	 *
	 * @param resourceLoader can be {@literal null}.
	 * @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader
	 * @since 1.8
	 */
	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		this.classLoader = classLoader;
	}
}

以下是方法的测试及结果:

                redisTemplate.opsForValue();//操作字符串,
                redisTemplate.opsForHash();//操作hash
                redisTemplate.opsForList();;//操作list
                redisTemplate.opsForSet();//操作set
                redisTemplate.opsForZSet();//操作有序set

    1.set void set(K key, V value); 

   使用:redisTemplate.opsForValue().set("name","tom");
   结果:redisTemplate.opsForValue().get("name")  输出结果为tom

 2. set void set(K key, V value, long timeout, TimeUnit unit);      

使用:redisTemplate.opsForValue().set("name","tom",10, TimeUnit.SECONDS);
结果:redisTemplate.opsForValue().get("name")由于设置的是10秒失效,十秒之内查询有结果,十秒之后返回为null

3. set void set(K key, V value, long offset);
 该方法是用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始        

使用:template.opsForValue().set("key","hello world");
template.opsForValue().set("key","redis", 6);
                            System.out.println("***************"+template.opsForValue().get("key"));
                    结果:***************hello redis

4.setIfAbsent Boolean setIfAbsent(K key, V value);         

使用:System.out.println(template.opsForValue().setIfAbsent("multi1","multi1"));//false  multi1之前已经存在
                            System.out.println(template.opsForValue().setIfAbsent("multi111","multi111"));//true  multi111之前不存在
 结果:false
      true

5.multiSet void multiSet(Map<? extends K, ? extends V> m);
                    为多个键分别设置它们的值

  使用:Map<String,String> maps = new HashMap<String, String>();
                            maps.put("multi1","multi1");
                            maps.put("multi2","multi2");
                            maps.put("multi3","multi3");
                            template.opsForValue().multiSet(maps);
                            List<String> keys = new ArrayList<String>();
                            keys.add("multi1");
                            keys.add("multi2");
                            keys.add("multi3");
                            System.out.println(template.opsForValue().multiGet(keys));
                    结果:[multi1, multi2, multi3]

6. multiSetIfAbsent Boolean multiSetIfAbsent(Map<? extends K, ? extends V> m);
                    为多个键分别设置它们的值,如果存在则返回false,不存在返回true

  使用:Map<String,String> maps = new HashMap<String, String>();
                            maps.put("multi11","multi11");
                            maps.put("multi22","multi22");
                            maps.put("multi33","multi33");
                            Map<String,String> maps2 = new HashMap<String, String>();
                            maps2.put("multi1","multi1");
                            maps2.put("multi2","multi2");
                            maps2.put("multi3","multi3");
                            System.out.println(template.opsForValue().multiSetIfAbsent(maps));
                            System.out.println(template.opsForValue().multiSetIfAbsent(maps2));
                    结果:true
                    false

 7.get V get(Object key);

                    使用:template.opsForValue().set("key","hello world");
                            System.out.println("***************"+template.opsForValue().get("key"));
                    结果:***************hello world

8.getAndSet V getAndSet(K key, V value); 设置键的字符串值并返回其旧值          

 使用:template.opsForValue().set("getSetTest","test");
                            System.out.println(template.opsForValue().getAndSet("getSetTest","test2"));
                    结果:test

9.multiGet List<V> multiGet(Collection<K> keys);  为多个键分别取出它们的值                      

  使用:Map<String,String> maps = new HashMap<String, String>();
                            maps.put("multi1","multi1");
                            maps.put("multi2","multi2");
                            maps.put("multi3","multi3");
                            template.opsForValue().multiSet(maps);
                            List<String> keys = new ArrayList<String>();
                            keys.add("multi1");
                            keys.add("multi2");
                            keys.add("multi3");
                            System.out.println(template.opsForValue().multiGet(keys));
                    结果:[multi1, multi2, multi3]

 10.get String get(K key, long start, long end);截取key所对应的value字符串         

 使用:appendTest对应的value为Helloworld
                    System.out.println("*********"+template.opsForValue().get("appendTest",0,5));
                    结果:*********Hellow
                    使用:System.out.println("*********"+template.opsForValue().get("appendTest",0,-1));
                    结果:*********Helloworld
                    使用:System.out.println("*********"+template.opsForValue().get("appendTest",-3,-1));
                    结果:*********rld

这写了十个常用的redis的操作的具体的其他操作等用到时会详细的加以说明。

文章参考:1.https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/core/RedisTemplate.html#afterPropertiesSet-- springdata官网

2.一个忘记的简书的一个笔者。
                   


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kay三石

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值