RedisTemplate

  1. Jedis与RedisTemplate的区别:
    Jedis是Redis官方推荐的面向Java的操作Redis的客户端,可以用JedisPool来获得连接进行get、set、del等操作相对简单,而RedisTemplate是SpringDataRedis中对JedisApi的高度封装。
    SpringDataRedis相对于Jedis来说可以方便地更换Redis的Java客户端,比Jedis多了自动管理连接池的特性,方便与其他Spring框架进行搭配使用如:SpringCache
    参考:https://blog.csdn.net/varyall/article/details/83476970

  2. redisTemplate与stringRedisTemplate的区别
    第一点,StringRedisTemplate继承了RedisTemplate。
    第二点,RedisTemplate是一个泛型类,而StringRedisTemplate则不是。
    第三点,StringRedisTemplate只能对key=String,value=String的键值对进行操作,RedisTemplate可以对任何类型的key-value键值对操作。
    第四点,是他们各自序列化的方式不同,但最终都是得到了一个字节数组,殊途同归,StringRedisTemplate使用的是StringRedisSerializer类;RedisTemplate使用的是JdkSerializationRedisSerializer类。反序列化,则是一个得到String,一个得到Object
    这两个类是springboot-data-redis对Redis进行操作的实现类。

    打开StringRedisTemplate和RedisTemplate的源码,发现StringRedisTemplate继承了RedisTemplate,一般来说子类应该比父类有用更强大的功能,而此处却不是,因为RedisTemplate是泛型类,而在StringRedisTemplate继承RedisTemplate类时,则是指定了泛型的类型,两个String。
    这就直接导致了,StringRedisTemplate只能处理String-String的键值对数据,而RedisTemplate则可以处理任何类型的键值对。

RedisTemplate源码:

public class RedisTemplate extends RedisAccessor implements RedisOperations, BeanClassLoaderAware {}

StringRedisTemplate源码:

public class StringRedisTemplate extends RedisTemplate {}

参考:https://jingyan.baidu.com/article/f7ff0bfcc5c4152e26bb13bc.html

  1. 序列化:
    redis中对序列化的应用主要是在四个方面,分别是
    keySerializer、valueSerializer、hashKeySerialiser、hashValueSerializer。可以从StringRedisTemplate的源码中体现出来:
/**
	 * Constructs a new StringRedisTemplate instance. {@link #setConnectionFactory(RedisConnectionFactory)}
	 * and {@link #afterPropertiesSet()} still need to be called.
	 */
	public StringRedisTemplate() {
		setKeySerializer(RedisSerializer.string());
		setValueSerializer(RedisSerializer.string());
		setHashKeySerializer(RedisSerializer.string());
		setHashValueSerializer(RedisSerializer.string());
	}

在redisTemplate中采用的序列化机制默认都是JdkSerializationRedisSerializer,源码:

	@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;
	}

而在StringRedisTemplate中默认采用的序列化机制是:StringRedisSerializer,源码:

/**
	 * Constructs a new StringRedisTemplate instance. {@link #setConnectionFactory(RedisConnectionFactory)}
	 * and {@link #afterPropertiesSet()} still need to be called.
	 */
	public StringRedisTemplate() {
		setKeySerializer(RedisSerializer.string());
		setValueSerializer(RedisSerializer.string());
		setHashKeySerializer(RedisSerializer.string());
		setHashValueSerializer(RedisSerializer.string());
	}
/**
	 * Obtain a simple {@link java.lang.String} to {@literal byte[]} (and back) serializer using
	 * {@link java.nio.charset.StandardCharsets#UTF_8 UTF-8} as the default {@link java.nio.charset.Charset}.
	 *
	 * @return never {@literal null}.
	 * @since 2.1
	 */
	static RedisSerializer string() {
		return StringRedisSerializer.UTF_8;
	}
	public static final StringRedisSerializer UTF_8 = new StringRedisSerializer(StandardCharsets.UTF_8);

无论是JdkSerializationRedisSerializer还是StringRedisSerializer都实现泛型接口RedisSerializer, 源码:

/**
 * Basic interface serialization and deserialization of Objects to byte arrays (binary data). It is recommended that
 * implementations are designed to handle null objects/empty arrays on serialization and deserialization side. Note that
 * Redis does not accept null keys or values but can return null replies (for non existing keys).
 *
 * @author Mark Pollack
 * @author Costin Leau
 * @author Christoph Strobl
 */
public interface RedisSerializer {}

/**
 * Java Serialization Redis serializer. Delegates to the default (Java based) {@link DefaultSerializer serializer} and
 * {@link DefaultDeserializer}. This {@link RedisSerializer serializer} can be constructed with either custom
 * {@link ClassLoader} or own {@link Converter converters}.
 *
 * @author Mark Pollack
 * @author Costin Leau
 * @author Mark Paluch
 * @author Christoph Strobl
 */
public class JdkSerializationRedisSerializer implements RedisSerializer {}

/**
 * Simple {@link java.lang.String} to {@literal byte[]} (and back) serializer. Converts {@link java.lang.String Strings}
 * into bytes and vice-versa using the specified charset (by default {@literal UTF-8}).
 * 

* Useful when the interaction with the Redis happens mainly through Strings. *

* Does not perform any {@literal null} conversion since empty strings are valid keys/values. * * @author Costin Leau * @author Christoph Strobl * @author Mark Paluch */ public class StringRedisSerializer implements RedisSerializer {}

除此外,spring-data-redis中还有几个也实现了RedisSerializer接口的序列化类,它们之间的区别如下:

  • GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化

  • Jackson2JsonRedisSerializer: 跟JacksonJsonRedisSerializer实际上是一样的

  • JacksonJsonRedisSerializer: 序列化object对象为json字符串,jackson-json工具提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。【需要jackson-mapper-asl工具支持】

  • JdkSerializationRedisSerializer: 序列化java对象(被序列化的对象必须实现Serializable接口),使用JDK本身序列化机制,将pojo类通ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。是目前最常用的序列化策略

  • StringRedisSerializer: 简单的字符串序列化,根据指定的charset对数据的字节序列编码成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。

  • GenericToStringSerializer:类似StringRedisSerializer的字符串序列化

  • GenericJackson2JsonRedisSerializer:类似Jackson2JsonRedisSerializer,但使用时构造函数不用特定的类

  • OxmSerializer:提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。【需要spring-oxm模块的支持】

  1. ObjectMapper介绍
    ObjectMapper类是Jackson库的主要类。它提供一些功能将转换成Java对象匹配JSON结构,反之亦然。它使用JsonParser和JsonGenerator的实例实现JSON实际的读/写。
ObjectMapper objectMapper = new ObjectMapper();
		
		/**序列化的时候序列对象的所有属性
		* Include.ALWAYS  是序列化对像所有属性
		* Include.NON_NULL 只有不为null的字段才被序列化
		* Include.NON_EMPTY 如果为null或者 空字符串和空集合都不会被序列化
		* /
		objectMapper.setSerializationInclusion(Include.ALWAYS); 
		
		//反序列化的时候如果多了其他属性,不抛出异常
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		
		//如果是空对象的时候,不抛异常
		objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
		
		//取消时间的转化格式,默认是时间戳,可以取消,同时需要设置要表现的时间格式
		objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
		objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))

		// 属性访问器可以访问任何属性,jackson的自动检测机制可以任何级别的字段都可以识别
		objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY)
		// 非final类型
		objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)

jackson 1.x和2.x版本的注解是放置在不同的包下的

1.x是在jackson core jar包org.codehaus.jackson.annotate下

2.x是在jackson-databind包com.fasterxml.jackson.annotation下
https://blog.csdn.net/xiaoyu411502/article/details/45001317

  1. 总结:
  • Jdk序列化速度快,占用空间大,不易查看,通过redis命令查看类似\xAC\xED\x00\x05t\x00\x011不方便,Hash最好还是用GenericJackson2JsonRedisSerializer
  • 可以通过手动配置, 将redisTemplate的序列化方式进行更改,推荐将所有Template的key都采用String的序列化方式,而value的序列化方式可以采用不同的序列化方式
  1. 注意:
  • RedisTemplate的key指定成StringRedisSerializer序列化会报类型转换错误,如XXX类不能转换成String。
  • 使用Jackson2JsonRedisSerializer序列化的时候,如果实体类上没有set方法反序列化会报错
  • 对于已存在redis中的数据,如果此时重新编写redisTemplate取获取数据,则一定要确认redis中的数类型,如果不能确认的,则默认使用StringRedisTemplate。因为取redis中反序列化的结果如果和存的不一致会抛异常,尽量保证项目中的redisTemplate保持不变
  1. spring redis的相关配置
spring.redis.host=
spring.redis.port=
# 连接池中最少空闲的连接数
spring.redis.jedis.pool.min-idle=
# 当连接池资源耗尽时,调用者最大的阻塞时间,超出时将抛出异常。单位:ms,默认-1,表示永不超时
spring.redis.jedis.pool.max-wait=
# 连接池的最大数据库连接数。设为0表示无限制,如果是jedis 2.4以后用redis.maxTotal
spring.redis.jedis.pool.max-active=
# 连接池中最大空闲的连接数数
spring.redis.jedis.pool.max-idle=
spring.redis.database=
spring.redis.timeout=
  1. 代码 https://github.com/baiyanlang2016/redisTemplate

你可能感兴趣的:(中间件)