黑马2022Redis教程
Redis命令官方文档
KEYS:查看符合模板的key(模糊查询),单线程,且不适合大规模的生产环境
返回值就是个数
到有效期后自动删除。Redis消耗的是内存空间,为了节省空间or满足应用场景(例如短信验证码就必须在几分钟之内确认)
单位是seconds
把一些小的总结写在前面 = =
类似Java中的HashMap
把String操作命令的开头加上H就是Hash类型的操作命令语句
无序不可重复,查询效率高;支持交集 并集 差集的功能
如下添加了黑马视频中“好友”案例的提示
可排序的Set类似TreeSet,且不可重复,查询快
底层是调表+hash表
每一个元素都必须有一个得分score属性,可以由此排序,可实现排行榜的功能
redis.clients
jedis
3.8.0
在Junit5中使用@BeforeEach来指定所有@Test之前的操作,@AfterEach来指定所有@Test结束之后的操作
Junit4中分别是@Before和@After
@SpringBootTest
class BootAjaxtestApplicationTests {
private Jedis jedis;//因为是new,所以无序@Autowired注入
@BeforeEach//任意@Test之前进行配置
public void connectRedis() {
jedis = new Jedis("124.xxx.xxx.176", 6379);//ip和端口
jedis.auth("xxxxxxx");//密码
jedis.select(1);//选择库
}
@AfterEach//任意@Test之后关闭连接
public void closeRedis() {
if (jedis != null) {
jedis.close();
}
}
@Test
public void redisTest1() {
//1.测试String
jedis.set("测试key", "测试value");
System.out.println(jedis.get("测试key"));
//2.测试Hash
jedis.hset("分层:Hash测试1", "属性1","111");
jedis.hset("分层:Hash测试1", "属性2","222");
jedis.hset("分层:Hash测试2", "属性a","aaa");
jedis.hset("分层:Hash测试2", "属性b","bbb");
System.out.println(jedis.hgetAll("分层:Hash测试2"));
}
}
虽然使用简单,但Jedis实例本身线程不安全,多线程环境下需要使用Jedis线程池
来替代Jedis
JedisConnectionFactory有一个静态方法getJedis,返回一个Jedis实例
配置的顺序是:JedisPoolConfig——JedisPool——getResource()返回Jedis实例
连接池JedisConnectionFactory如下:
public class JedisConnectionFactory {
//在static静态代码块中初始化
private static final JedisPool pool;
//静态代码块,随类的加载而加载
static{
//1.jedis连接池配置类
JedisPoolConfig config = new JedisPoolConfig();
//1.1可用连接实例的最大数目,默认值为8;
config.setMaxTotal(10);
//1.2控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值8。
//设置没人访问时,最多有5个空闲;设置太大占内存
config.setMaxIdle(5);
//1.3pool的最小idle数,默认为8
//设置没人访问时,释放连接数的底线;设置太小无法快速应对突然的请求
config.setMinIdle(3);
//1.4设置最长等待时间,当池中没有线程可用时,超出时间就报错
//-1表示无限等待,这里设置为1000ms
config.setMaxWaitMillis(1000);
//2.创建连接池对象,形参为(上面的配置类对象config,ip,端口,连接超时时间,密码)
pool = new JedisPool(config, "xxx.xxx.xxx.xxx", 6379, 1000, "xxxxxxxx");
}
//3.静态方法:从pool中获取一个资源(实例)
public static Jedis getJedis(){
return pool.getResource();
}
}
为什么引入?:Jedis虽然学习成本低,但不同的数据结构对应的不同方法实在是太多了,显得十分臃肿;
引入SpringDataRedis,其中提供了工具类RedisTemplate,封装了各种Redis操作
该案例基于springboot
注意区别之前的Jedis依赖,这两个是新的依赖
那么什么时候需要之前那个Jedis依赖呢?:springboot默认的是lettuce依赖,所以使用lettuce作为连接池时不需要Jedis依赖;但如果是想使用Jedis作为连接池,就需要引入之前的Jedis依赖
org.springframework.boot
spring-boot-starter-data-redis
org.apache.commons
commons-pool2
第一个是springboot对redis整合,第二个是底层连接池(无论是lettuce还是jedis都需要这个依赖)
springboot对redis进行了整合,因此可以直接在application.yaml中进行配置
一定要手动配置
直接@Autowired
@SpringBootTest
class BootAjaxtestApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void redisTest1(){
redisTemplate.opsForValue().set("张三","18");
//形参可以任意类,RedisTemplate自动序列化(默认使用JDK的序列化工具)
System.out.println(redisTemplate.opsForValue().get("张三"));
}
}
这个键值对中key指定的是“张三”,但在redis中存储的是一串字符串编码,占用了十分多的空间,并且可读性差
这是由于:使用了原生的JDK序列化器JdkSerializationRedisSerializer
由于我们并没有对工具类RedisTemplate进行任何修改而直接使用,因此我们进入源码进行分析
默认序列化器defaultSerializer = null ;
默认使用JDK序列化器
JDK序列化器JdkSerializationRedisSerializer的内核是对象流:把对象存储为字节码的形式,而不是文本,因此看到的必然乱码,同理用对象流保存数据到txt文件中也会乱码
序列化协议参考
参考2
序列化协议有很多,流行的有:
jdk的序列化,就是序列化成字节流通过网络传输到redis里面存起来,但是你查出来的就是直接序列化的你看不懂的字节流的形式,默认是十六进制数据
而其他满足JSON协议的序列化器,序列化成字节流通过网络传输到redis里面存起来的同时,还可以转化为字符串,让人类能够看得懂,本质上还是序列化
redis要序列化对象是使对象可以跨平台存储和进行网络传输。因为存储和网络传输都需要把一个对象状态保存成一种跨平台识别的字节格式,然后其他的平台才可以通过字节信息解析还原对象信息,所以进行“跨平台存储”和”网络传输”的数据都需要进行序列化。
JSON序列化器会把@class的类路径信息也进行包装传输,非常浪费时间,因此不能用JSON序列化器来传输对象
**使用StringRedisTemplate工具类(注意不是StringRedisSerializer序列化器)**来传输String字符串
ps:查看源码可知StringRedisTemplate是RedisTemplate的子类,配置好了键值对都必须是String
StringRedisTemplate本质是一个配置好String序列化器的RedisTemplate
具体操作步骤可以稍微参考下我的这一篇笔记,或者搜一下”如何导入FastJson“
操作步骤
或者参考菜鸟教程
Managers managers = new Managers();
managers.setSex("男");
managers.setAge(18);
managers.setName("张三");
String s = JSON.toJSONString(managers);
System.out.println(s);
示例:
@SpringBootTest
class BootAjaxtestApplicationTests {
//1.注入String序列化模板
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void test1(){
Managers managers = new Managers();
managers.setSex("男");
managers.setAge(18);
managers.setName("张三");
//2.fastjson序列化对象
String s = JSON.toJSONString(managers);
//3.写入数据到redis
stringRedisTemplate.opsForValue().set("test张三", s);
//4.读取数据并反序列化
String r = stringRedisTemplate.opsForValue().get("test张三");
Managers managers1 = JSON.parseObject(r, Managers.class);
System.out.println(managers1);//Managers(name=张三, sex=男, age=18)
}}
测试:
@Test
public void test2(){
Managers managers = new Managers();
managers.setSex("男");
managers.setAge(18);
managers.setName("李四");
stringRedisTemplate.opsForHash().put("test李四", "id","1111" );
stringRedisTemplate.opsForHash().put("test李四", "manager", JSON.toJSONString(managers));
Map