【开发篇】七、RedisTemplate与StringRedisTemplate + Jedis与Lettcus

文章目录

  • 1、RedisTemplate详解
  • 2、常用方法
  • 3、关于IDEA的报黄
  • 4、RedisTemplate和StringRedisTemplate的区别
  • 5、如何通用RedisTemplate和StringRedisTemplate
  • 6、Jedis
  • 7、Jedis的连接池
  • 8、封装Jedis工具类
  • 8、RedisTemplate底层实现技术切换

【开发篇】七、RedisTemplate与StringRedisTemplate + Jedis与Lettcus_第1张图片

1、RedisTemplate详解

RedisTemplate是Spring Data Redis提供的一个用于与Redis交互的高级工具类。它封装了与Redis服务器通信的底层细节,并提供了许多方便的方法来操作Redis的各种数据结构。

  • RedisTemplate基于Jedis或Lettuce等连接池技术,实现了与Redis服务器的连接和资源管理
  • 类中定义了一系列方法,可处理Redis的各种数据结构和执行各种Redis命令
  • RedisTemplate内部使用序列化器将Java对象转换为字节数组,并将其存储到Redis中。同时,还负责将从Redis中获取的字节数组转换回Java对象
//关于K,V
@Autowired
RedisTemplate<K,V> redisTemplate;

当使用RedisTemplate操作Redis时,K的类型通常是String类型,即键的数据类型为字符串。而V的类型可以是任意类型,取决于你存储的实际数据。RedisTemplate支持多种数据结构,例如字符串、哈希、列表、集合、有序集合等,因此V的类型可以是String、Hash、List、Set、ZSet等,RedisTemplate提供操作各种数据存储类型的接口API,不同类型调用不同方法:

【开发篇】七、RedisTemplate与StringRedisTemplate + Jedis与Lettcus_第2张图片

2、常用方法

存取不同类型的value数据,调用方法获取不同类型的操作对象:

#1opsForValue()

返回一个用于操作String类型的ValueOperations对象,可以对Redis中的字符串键值对进行操作

#2opsForHash()

返回一个用于操作Hash类型的HashOperations对象,可以对Redis中的哈希数据结构进行操作

#3opsForList()

返回一个用于操作List类型的ListOperations对象,可以对Redis中的列表数据结构进行操作

#4opsForSet()

返回一个用于操作Set类型的SetOperations对象,可以对Redis中的集合数据结构进行操作

#5opsForZSet()

返回一个用于操作Sorted Set类型的ZSetOperations对象,可以对Redis中的有序集合数据结构进行操作


#6execute(RedisCallback)

用于执行自定义的Redis操作,可以通过实现RedisCallback接口来自定义要执行的操作

当你调用RedisTemplate的opsForValue()方法时,返回的实例可以用于操作字符串值;调用opsForHash()方法时,可以操作哈希类型的值;调用opsForList()方法时,可以操作列表类型的值;

总之就是,要操作什么类型的Redis数据,就调opsForxxx()方法获取什么类型的Operations对象,完了用这个对象调用set、get、hget等方法就行。

3、关于IDEA的报黄

【开发篇】七、RedisTemplate与StringRedisTemplate + Jedis与Lettcus_第3张图片

4、RedisTemplate和StringRedisTemplate的区别

二者都是Spring封装好的操作操作Redis的工具对象,从源码来看为:

public class StringRedisTemplate extends RedisTemplate<String,String> {
	//.....
}

即:

  • 两者的关系是StringRedisTemplate继承RedisTemplate

  • RedisTemplate以对象作为key和value,内部对数据进行序列化

  • StringRedisTemplate以字符串作为key和value,与Redis客户端操作等效

  • 存取数据时,序列化的方式不同,互相查不到对方写进来的数据,导致了二者只能各自管各自的数据,给人一种它们数据不互通的感觉,但其实是同一个redis库

  • SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略

详细说就是:

  • RedisTemplate使用的是JdkSerializationRedisSerializer存入数据,会将数据先序列化成字节数组,然后在存入Redis数据库
  • 如果数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那选择RedisTemplate最优

所以,我们看到redisTemplate对象存进去的数据在客户端长这样:
【开发篇】七、RedisTemplate与StringRedisTemplate + Jedis与Lettcus_第4张图片

此时就有个问题,我们用RedisTemplate从Redis里get查数据时,也是默认将数据当作字节数组来转成对象或可读字符串。那如果redis里存的key本身就是可读的字符串,再当字节数组来转换就会获取不到数据,由此,StringRedisTemplate出现

StringRedisTemplate使用的是StringRedisSerializer,当你的redis数据库里面本来存的是字符串数据,或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可。

当redis中存入的数据是可读形式而非字节数组时,使用redisTemplate取值的时候会无法获取导出数据,获得的值为null,此时就可以使用 StringRedisTemplate 试试,同理,使用RedisTemplate来set进去的数据,用StringRedisTemplate也无法获取。

5、如何通用RedisTemplate和StringRedisTemplate

二者存取的差异在于key和value的序列化处理类,想实现混用redisTemplate和stringRedisTemplate,就得指定统一的key和Value的序列化处理类,如,让RedisTemplate序列化时,使用StringRedisTemplate的StringRedisSerializer。

//示例,这块在旧项目里应该是祖传的,新项目的话借鉴下若依框架吧
@Configuration
public class RedisConfig{
	@Bean
	public RedisTemplate<Object, Object> redisSessionTemplate(RedisConnectionFactory factory) {
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		// 配置连接工厂
		template.setConnectionFactory(factory);
		//JdkSerializationRedisSerializer jdkRedisSerializer = new JdkSerializationRedisSerializer();
		RedisSerializer<String> keySerializer = new StringRedisSerializer();
		RedisSerializer<Object> valueSerializer = new JdkSerializationRedisSerializer(this.getClass().getClassLoader());
		// 值采用json序列化
		template.setValueSerializer(valueSerializer);
		//使用StringRedisSerializer来序列化和反序列化redis的key值
		template.setKeySerializer(keySerializer);
		// 设置hash key 和value序列化模式
		template.setHashKeySerializer(keySerializer);
		template.setHashValueSerializer(valueSerializer);
		template.afterPropertiesSet();
		return template;
	}
}

6、Jedis

  • Jedis就是Redis官方推荐的Java连接开发工具。

  • 在Java中,Redis对应于Jedis就相当于关系数据库对应于JDBC!!!

使用实例,首先引入依赖:

<dependency>
    <groupId>redis.clientsgroupId>
    <artifactId>jedisartifactId>
dependency>

对于不用认证的redis,直接new一个Jedis对象,调用与指令名相同的API来完成数据操作即可:

// 第一个参数是Redis的IP地址,第二个参数是Redis的端口号
Jedis jedis = new Jedis("localhost", 6379);
// 写
jedis.set("msg", "Hello World!");
//查
String msg = jedis.get("msg");	
// 打印Hello World
System.out.println(msg);	
// 关闭Redis连接
jedis.close();

有认证的则:

Jedis jedis = new Jedis("localhost", 6379);

jedis.auth("password");

//auth方法重载
jedis.auth("username","password");

或者借助JedisShardInfo对象:

JedisShardInfo info = new JedisShardInfo("localhost",6379);

info.setPassword("admin123");

Jedis jedis  = new Jedis(info);

jedis.get("xxx")

7、Jedis的连接池

Jedis提供了连接池机制,需要操作Redis数据时,向Jedis连接池获取Redis的连接对象即可(类比JDBC的Connection对象),Jedis的连接池类为redis.clients.jedis.JedisPool。

// 初始化连接池类(使用默认连接池参数)
//JedisPool构造方法重载,你再传用户名密码也行
JedisPool jp = new JedisPool("localhost", 6379);

// 获取一个Jedis连接
Jedis jedis = jp.getResource();

也可使用配置类JedisPoolConfig来指定连接池的其他参数:

JedisPoolConfig jpc = new JedisPoolConfig();

// 设置连接池的最大连接数
jpc.setMaxTotal(30);  

// 设置连接池允许的最大空闲连接数
jpc.setMaxIdle(8);    

// 初始化连接池类,传入使用自定义连接池配置类
JedisPool jp = new JedisPool(jpc, "localhost", 6379);

// 从连接池获取一个Jedis连接
Jedis jedis = jp.getResource();

8、封装Jedis工具类

封装个工具类,方便后续使用,jedis.properties内容:

jedis.host=localhost
jedis.port=6379
jedis.username=admin
jedis.password=admin123
jedis.maxTotal=30
jedis.maxIdle=10

借助静态代码块,调用封装的静态方法获取连接对象时,执行静态代码块,完成连接池初始化。(复习:静态代码块在类加载时执行,且执行一次,而调用静态资源是类加载的触发时机之一)

public class JedisUtils {
	private static JedisPool pool;
	
	static {
		// 加载Jedis连接池配置参数
		InputStream inputStream = JedisUtils.class.getResourceAsStream("jedis.properties");
		Properties prop = new Properties();
		try {
			prop.load(inputStream);
		} catch (IOException e) {
			e.printStackTrace();
		}
		String host = prop.getProperty("jedis.host");
		int port = Integer.parseInt(prop.getProperty("jedis.port"));
		int maxTotal = Integer.parseInt(prop.getProperty("jedis.maxTotal"));
		int maxIdle = Integer.parseInt(prop.getProperty("jedis.maxIdle"));
		String username = prop.getProperty("jedis.username");
		String password = prop.getProperty("jedis.password");
		
		// 设置Jedis连接池参数
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxTotal(maxTotal);
		config.setMaxIdle(maxIdle);
		
		// 初始化Jedis连接池
		pool = new JedisPool(config, host, port,username,password);
	}
	
	// 从Jedis连接池获取连接
	public static Jedis getJedis() {
		return pool.getResource();
	}
}

8、RedisTemplate底层实现技术切换

RedisTemplate基于Jedis或Lettuce等连接池技术,实现了与Redis服务器的连接和资源管理。且SpringBoot下默认是使用Lettuce,这一点从starter中可以看到:

在这里插入图片描述

想实现底层技术的切换,即从默认的lettuce(翻译:生菜)切换成Jedis,只需引入依赖后指定配置中的client-type即可:

<dependency>
    <groupId>redis.clientsgroupId>    
    <artifactId>jedisartifactId>
dependency>

改配置,准确说是在原来的基础说改下client-type:

spring:  
  redis:    
    host: localhost     
    port: 6379    
    client-type: jedis

其余独有属性可单独配置,Jedis和Lettuce的常用配置如连接池最大连接数:

spring:  
  redis:    
    host: localhost     
    port: 6379    
    client-type: jedis
    jedis:
      pool:
        max-active: 16
    # 顺便展示下Lettuce的,写一起了
    lettuce:
      pool:
        max-active: 16

关于Lettuce和Jedis的区别:

  • jedis连接Redis服务器是直连模式,当多线程模式下使用jedis会存在线程安全问题,解决方案可以通过配置连接池使每个连接专用,这样整体性能就大受影响
  • lettcus基于Netty框架进行与Redis服务器连接,底层设计中采用StatefulRedisConnection。 StatefulRedisConnection自身是线程安全的,可以保障并发访问安全问题,所以一个连接可以被多线程复用,当然lettcus也支持多连接实例一起工作

线程安全的这一点区别,大概就是Lettuce被选中做starter的默认实现的原因吧。

你可能感兴趣的:(SpringBoot,SpringBoot,Jedis,RedisTemplate)