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



    在这里插入图片描述

    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;
    
    • 1
    • 2
    • 3

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

    在这里插入图片描述

    2、常用方法

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

    #1opsForValue()
    
    • 1

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

    #2opsForHash()
    
    • 1

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

    #3opsForList()
    
    • 1

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

    #4opsForSet()
    
    • 1

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

    #5opsForZSet()
    
    • 1

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


    #6execute(RedisCallback)
    
    • 1

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

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

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

    3、关于IDEA的报黄

    在这里插入图片描述

    4、RedisTemplate和StringRedisTemplate的区别

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

    public class StringRedisTemplate extends RedisTemplate<String,String> {
    	//.....
    }
    
    • 1
    • 2
    • 3

    即:

    • 两者的关系是StringRedisTemplate继承RedisTemplate

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

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

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

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

    详细说就是:

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

    所以,我们看到redisTemplate对象存进去的数据在客户端长这样:
    在这里插入图片描述

    此时就有个问题,我们用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;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    6、Jedis

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

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

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

    <dependency>
        <groupId>redis.clientsgroupId>
        <artifactId>jedisartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    对于不用认证的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();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    有认证的则:

    Jedis jedis = new Jedis("localhost", 6379);
    
    jedis.auth("password");
    
    //auth方法重载
    jedis.auth("username","password");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    或者借助JedisShardInfo对象:

    JedisShardInfo info = new JedisShardInfo("localhost",6379);
    
    info.setPassword("admin123");
    
    Jedis jedis  = new Jedis(info);
    
    jedis.get("xxx")
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    JedisPoolConfig jpc = new JedisPoolConfig();
    
    // 设置连接池的最大连接数
    jpc.setMaxTotal(30);  
    
    // 设置连接池允许的最大空闲连接数
    jpc.setMaxIdle(8);    
    
    // 初始化连接池类,传入使用自定义连接池配置类
    JedisPool jp = new JedisPool(jpc, "localhost", 6379);
    
    // 从连接池获取一个Jedis连接
    Jedis jedis = jp.getResource();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    8、封装Jedis工具类

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

    jedis.host=localhost
    jedis.port=6379
    jedis.username=admin
    jedis.password=admin123
    jedis.maxTotal=30
    jedis.maxIdle=10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    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();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    8、RedisTemplate底层实现技术切换

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

    在这里插入图片描述

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

    <dependency>
        <groupId>redis.clientsgroupId>    
        <artifactId>jedisartifactId>
    dependency>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    spring:  
      redis:    
        host: localhost     
        port: 6379    
        client-type: jedis
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    spring:  
      redis:    
        host: localhost     
        port: 6379    
        client-type: jedis
        jedis:
          pool:
            max-active: 16
        # 顺便展示下Lettuce的,写一起了
        lettuce:
          pool:
            max-active: 16
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    关于Lettuce和Jedis的区别:

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

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

  • 相关阅读:
    测试所需文档
    【计算机网络】网络编程 Socket
    单片机的调试接口 JTAG SWD
    ElasticSearch-全文检索和分析引擎学习Day01
    [SQL Server]在应使用条件的上下文(在 ‘)‘ 附近)中指定了非布尔类型的表达式,查询时间大于某个数值时
    gitHub添加ssh
    基于改进樽海鞘群寻优SVM的土壤含水量预测算法
    github action 基于个人项目实践
    HDU - 1114 Piggy-Bank(完全背包)
    第十章《日期与时间》第3节:Java8新日期时间系统简介
  • 原文地址:https://blog.csdn.net/llg___/article/details/133280516