RedisTemplate是Spring Data Redis提供的一个用于与Redis交互的高级工具类。它封装了与Redis服务器通信的底层细节,并提供了许多方便的方法来操作Redis的各种数据结构。
//关于K,V
@Autowired
RedisTemplate<K,V> redisTemplate;
当使用RedisTemplate操作Redis时,K的类型通常是String类型,即键的数据类型为字符串。而V的类型可以是任意类型,取决于你存储的实际数据。RedisTemplate支持多种数据结构,例如字符串、哈希、列表、集合、有序集合等,因此V的类型可以是String、Hash、List、Set、ZSet等,RedisTemplate提供操作各种数据存储类型的接口API,不同类型调用不同方法:
存取不同类型的value数据,调用方法获取不同类型的操作对象:
#1、opsForValue()
返回一个用于操作String类型的ValueOperations对象,可以对Redis中的字符串键值对进行操作
#2、opsForHash()
返回一个用于操作Hash类型的HashOperations对象,可以对Redis中的哈希数据结构进行操作
#3、opsForList()
返回一个用于操作List类型的ListOperations对象,可以对Redis中的列表数据结构进行操作
#4、opsForSet()
返回一个用于操作Set类型的SetOperations对象,可以对Redis中的集合数据结构进行操作
#5、opsForZSet()
返回一个用于操作Sorted Set类型的ZSetOperations对象,可以对Redis中的有序集合数据结构进行操作
#6、execute(RedisCallback)
用于执行自定义的Redis操作,可以通过实现RedisCallback接口来自定义要执行的操作
当你调用RedisTemplate的opsForValue()方法时,返回的实例可以用于操作字符串值;调用opsForHash()方法时,可以操作哈希类型的值;调用opsForList()方法时,可以操作列表类型的值;
总之就是,要操作什么类型的Redis数据,就调opsForxxx()方法获取什么类型的Operations对象,完了用这个对象调用set、get、hget等方法就行。
二者都是Spring封装好的操作操作Redis的工具对象,从源码来看为:
public class StringRedisTemplate extends RedisTemplate<String,String> {
//.....
}
即:
两者的关系是StringRedisTemplate继承RedisTemplate
RedisTemplate以对象
作为key和value,内部对数据进行序列化
StringRedisTemplate以字符串
作为key和value,与Redis客户端操作等效
存取数据时,序列化的方式不同,互相查不到对方写进来的数据,导致了二者只能各自管各自的数据,给人一种它们数据不互通的感觉,但其实是同一个redis库
SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略
详细说就是:
所以,我们看到redisTemplate对象存进去的数据在客户端长这样:
此时就有个问题,我们用RedisTemplate从Redis里get查数据时,也是默认将数据当作字节数组来转成对象或可读字符串。那如果redis里存的key本身就是可读的字符串,再当字节数组来转换就会获取不到数据,由此,StringRedisTemplate出现
。
StringRedisTemplate使用的是StringRedisSerializer,当你的redis数据库里面本来存的是字符串数据,或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可。
当redis中存入的数据是可读形式而非字节数组时,使用redisTemplate取值的时候会无法获取导出数据,获得的值为null,此时就可以使用 StringRedisTemplate 试试,同理,使用RedisTemplate来set进去的数据,用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;
}
}
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");
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();
封装个工具类,方便后续使用,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();
}
}
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会存在线程安全问题
,解决方案可以通过配置连接池使每个连接专用,这样整体性能就大受影响可以保障并发访问安全问题
,所以一个连接可以被多线程复用,当然lettcus也支持多连接实例一起工作线程安全的这一点区别,大概就是Lettuce被选中做starter的默认实现的原因吧。