一、简介
redis是一个非关系型数据库NoSQL(No Structured Query Language)数据库,数据以键值对存在(key 和 value)
(一)非关系型数据库简识
1.结构化与非结构化

像如上,该表便被各种条件框定住而写死了,该列的值一定是什么特性,是什么类型,这样就实现了结构化

redis的键值对型(包括以json数据作为值)数据存储,不固定值的类型和特性
2.关联的与非关联的

sql中,如上表,一个order通过user_id item_id 两个值关联了两个表,使得两个表中的单独对任一表的修改是会关联传递的

如redis中,像刚刚的order订单表,在redis中被以json嵌套的形式存储记录,张三的订单和李四的订单内容是单独例开的
3.在事务的差别
在sql数据库中,满足ACID(Atomicity原子性 Consistency一致性 Isolation隔离性 Durability持久性)理论
在nosql数据库中,只能满足基本的一致,即BASE理论
(二)redis简介
特征:
键值型数据存储
单线程,每条命令具备原子性,不受下一条命令入侵
低延迟,速度快(基于内存,IO多路复用)
支持数据持久化
支持主从集群、分片集群,即从节点可以备份主节点数据,主从节点可以做读写分离;分片,即数据拆分,存储到不同节点
支持多语言客户端
二、数据结构
key-value类型,key一般为string,但是value可以各种各样,包括string,hash,List,Set,SortedSet五种基本类型,BigMap,HyperLog,GEO三种特殊类型
三、命令
redis是通过命令行进行操作数据库的,对不同的类型数据的命令也不尽相同,在官网(https://redis.io/commands)可查看
四、Redis的Java客户端
(一)分类
1.Jedis
是以命令作为方法名称,所以简单使用,学习成本低。但是Jedis实例是线程不安全的,多线程下需要基于连接池来使用
2.Lettuce
是基于Netty实现的,支持同步、异步和响应式编程方式,而且线程安全的,支持redis的哨兵模式、集群模式和管道模式,推荐使用
Spring整合了Jedis和Lettuce为SpringDataRedis
(二)Jedis入门
1.引入依赖
进入Jedis官网查看自己jdk和redis版本适配的jedis版本,我jdk21
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>5.2.0</version>
</dependency>
2.建立连接
Jedis类是jedis客户端依赖中自带的类
3.测试String
4.释放资源
package com.itheima.test;import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;public class JedisTest {private Jedis jedis;@BeforeEachvoid setUp(){//1.建立连接jedis = new Jedis("127.0.0.1",6379);//2.设置密码jedis.auth("123456");//3.选择库jedis.select(0);}@Testvoid testString(){//存入数据String result = jedis.set("name", "虎哥");System.out.println("result = "+ result);//获取数据String name = jedis.get("name");System.out.println("name = "+ name);}@AfterEachvoid tearDown(){//释放空间if(jedis != null){jedis.close();}}
}
(三)Jedis连接池
Jedis本身是线程不安全的,且频繁的创建和销毁连接会有性能损耗,推荐使用Jedis连接池代替Jedis直连的方式
创建连接池工厂:
package com.itheima.jedis.util;import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;import java.time.Duration;public class JedisConnectionFactory {private static final JedisPool jedisPool;static {//配置连接池JedisPoolConfig poolConfig = new JedisPoolConfig();poolConfig.setMaxTotal(8);//最大连接数poolConfig.setMaxIdle(8);//最大空闲连接,即便没有人连接,池子里也可以预备这么多的连接,而不用重新建立poolConfig.setMinIdle(0);//最小空闲连接数,超过一段时间后如果连接一直没被人连接,则释放,直到最低值poolConfig.setMaxWait(Duration.ofMillis(1000));//等待时长//poolConfig.setMaxWaitMillis(1000); 该方法被遗弃,用Duration.of....标识时间//创建连接池对象jedisPool = new JedisPool(poolConfig,"127.0.0.1",6379,1000,"123456");}public static Jedis getJedis(){return jedisPool.getResource();}
}
然后在jedis连接类就可以修改建立连接的方法为获取连接池
@BeforeEachvoid setUp(){//1.建立连接
// jedis = new Jedis("127.0.0.1",6379);jedis = JedisConnectionFactory.getJedis();//2.设置密码jedis.auth("123456");//3.选择库jedis.select(0);}
(四)SpringDataRedis入门
根据spring.io官网的信息,目前最新正式版的SpringDataRedis为3.4.0
特点(简述)
对Jedis和Lettuce的整合,提供了RedisTemplate统一API来操作Redis,支持基于JDK、Json、字符串、Spring对象的数据序列化及反序列化,支持基于Redis的JDKCollection实现
(五)RedisTemplate工具类
在该工具类内封装了各种对Redis的操作,并将不同的数据类型的操作API封装到了不同的类型中:
1.引入依赖
使用idea自带的springboot的initializr,插件处勾选lombok和SpringDataRedis(Access+Driver)即可
然后引入commons-pool依赖,因为jedis和lettuce都基于这个池
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 连接池依赖 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency></dependencies>
2.配置文件
spring:application:name: RedisTemplateDemodata:redis:host: 127.0.0.1port: 6379password: 123456lettuce:pool:max-active: 8 #最大连接max-idle: 8 #最大空闲min-idle: 0 #最小空闲max-wait: 100 #连接等待时间,单位毫秒
3.注入RedisTemplate
4.编写测试
@SpringBootTest
class RedisTemplateDemoApplicationTests {@Autowiredprivate RedisTemplate redisTemplate;@Testvoid contextLoads() {//写入一条String数据redisTemplate.opsForValue().set("name","Jack");// 获取String数据Object name = redisTemplate.opsForValue().get("name");System.out.println("name = "+ name);}}
(六)RedisTemplate的序列化RedisSerializer
RedisTemplate可以接受任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是OutputStream输出流形式,缺点是:
可读性差 内存占用较大
所以我们改变默认的序列化方法
有两种:
StringRedisSerializer 用于string
GenericJackson2JacksonRedisSerializer 用于其他值
1.自定义序列化方式
package com.heima.redistemplatedemo.redis.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){// 创建RedisTemplate对象RedisTemplate<String, Object> template = new RedisTemplate<>();//设置连接工厂template.setConnectionFactory(connectionFactory);//创建Json序列化工具GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();//设置Key的序列化template.setKeySerializer(RedisSerializer.string());template.setHashKeySerializer(RedisSerializer.string());//设置Value的序列化template.setValueSerializer(jsonRedisSerializer);template.setHashValueSerializer(jsonRedisSerializer);//返回return template;}
}
2.通过自定义序列化方式存储中文字符串
@Testvoid contextLoads() {//写入一条String数据redisTemplate.opsForValue().set("name","虎哥");// 获取String数据Object name = redisTemplate.opsForValue().get("name");System.out.println("name = "+ name);}
3.通过自定义序列化方式存储对象
@Testvoid testSaveUser(){//写入数据redisTemplate.opsForValue().set("user:100",new User("虎哥",21));//获取数据User o = (User) redisTemplate.opsForValue().get("user:100");System.out.println("o = "+ o);}
4.序列化与反序列化——StringRedisTemplate类
用json序列化器存储数据,为了方便反序列化,会存储其类的class路径,这在数据量庞大时占用了大量内存
为了节省内存空间,我们并不会用json序列化器来处理Value,而是统一使用String序列化器,要求只存储String类型的key和value。当真的需要存储Java对象时,手动完成对象的序列化和反序列化
不过,好消息,Spring默认提供了一个StringRedisTemplate类,它的key和value序列化方式默认是String,省去了我们配置自定义RedisTemplate的时间
package com.heima.redistemplatedemo;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.heima.redistemplatedemo.redis.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;@SpringBootTest
class RedisStringTests {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testvoid contextLoads() {//写入一条String数据stringRedisTemplate.opsForValue().set("name","虎哥");// 获取String数据Object name = stringRedisTemplate.opsForValue().get("name");System.out.println("name = "+ name);}//SpringMvc中默认使用的Json处理工具private static final ObjectMapper mapper = new ObjectMapper();@Testvoid testSaveUser() throws JsonProcessingException {//创建对象User user = new User("虎哥",21);//手动序列化String json = mapper.writeValueAsString(user);//写入数据stringRedisTemplate.opsForValue().set("user:200",json);//获取数据String jsonUser = stringRedisTemplate.opsForValue().get("user:200");//手动反序列化mapper.readValue(jsonUser, User.class);//手动将该string按照User格式反序列化System.out.println("JsonUser = "+ jsonUser);}}
以后可以通过手动打包手动序列化和反序列化的进程,进一步简化代码
