如果使用率较低,就没必要写入缓存。
(2)该业务是读操作多,还是写操作多?
如果写操作多,频繁需要写入数据库,也没必要使用缓存。
(3)业务数据大小如何?
如果要存储几百兆字节的文件,会给缓存带来很大的压力,这样也没必要。
在考虑了这些问题之后,如果觉得有必要使用缓存,那么就使用它!使用 Redis 作为缓存的读取逻辑如下图所示:
从上图我们可以知道以下两点:
(1)当第一次读取数据的时候,读取Redis的数据就会失败,此时就会触发程序读取数据库,把数据读取出来,并且写入Redis中
(2)当第二次以及以后需要读取数据时,就会直接读取Redis,读取数据后就结束了流程,这样速度大大提高了。
从上面的分析可以知道,读操作的可能性是远大于写操作的,所以使用 Redis 来处理日常中需要经常读取的数据,速度提升是显而易见的,同时也降低了对数据库的依赖,使得数据库的压力大大减少。
分析了读操作的逻辑,下面我们来看看写操作流程:
从流程可以看出,更新或者写入的操作,需要多个 Redis 的操作,如果业务数据写次数远大于读次数那么就没有必要使用 Redis。
2、高速读写场合
在如今的互联网中,越来越多的存在高并发的情况,比如天猫双11、抢红包、抢演唱会门票等,这些场合都是在某一个瞬间或者是某一个短暂的时刻有成千上万的请求到达服务器,如果单纯的使用数据库来进行处理,就算不崩,也会很慢的,轻则造成用户体验极差用户量流水,重则数据库瘫痪,服务宕机,而这样的场合都是不允许的!
所以我们需要使用 Redis 来应对这样的高并发需求的场合,我们先来看看一次请求操作的流程:
我们来进一步阐述这个过程:
(1)当一个请求到达服务器时,只是把业务数据在Redis上进行读写,而没有对数据库进行任何的操作,这样就能大大提高读写的速度,从而满足高速相应的需求。
(2)但是这些缓存的数据仍然需要持久化,也就是存入数据库之中,所以在一个请求操作完Redis的读写之后,会去判断该高速读写的业务是否结束,这个判断通常会在秒杀商品为0,红包金额为0时成立,如果不成立,则不会操作数据库;如果成立,则触发事件将Redis的缓存的数据以批量的形式一次性写入数据库,从而完成持久化的工作。
四、在java中使用Redis
===============
1、添加Jedis依赖
想要在 Java 中使用 Redis 缓存,需要添加相关的Jar包依赖,打开Maven仓库的网站:https://mvnrepository.com/ ,搜索Jedis:
把它导入工程中去就可以啦,下面我们来对Redis的写入性能做一下测试:
@Test
public void redisTester() {
Jedis jedis = new Jedis("localhost", 6379, 100000);
int i = 0;
try {
long start = System.currentTimeMillis();// 开始毫秒数
while (true) {
long end = System.currentTimeMillis();
if (end - start >= 1000) {// 当大于等于1000毫秒(相当于1秒)时,结束操作
break;
}
i++;
jedis.set("test" + i, i + "");
}
} finally {// 关闭连接
jedis.close();
}
// 打印1秒内对Redis的操作次数
System.out.println("redis每秒操作:" + i + "次");
}
-----------测试结果-----------
redis每秒操作:10734次
2、使用Redis连接池
跟数据库连接池相同,Java Redis也同样提供了类 redis.clients.jedis.JedisPool
来管理我们的Reids连接池对象,并且我们可以使用 redis.clients.jedis.JedisPoolConfig
来对连接池进行配置,代码如下:
JedisPoolConfig poolConfig = new JedisPoolConfig();
// 最大空闲数
poolConfig.setMaxIdle(50);
// 最大连接数
poolConfig.setMaxTotal(100);
// 最大等待毫秒数
poolConfig.setMaxWaitMillis(20000);
// 使用配置创建连接池
JedisPool pool = new JedisPool(poolConfig, "localhost");
// 从连接池中获取单个连接
Jedis jedis = pool.getResource();
// 如果需要密码
//jedis.auth("password");
Redis只能支持六种数据结构 (string/hash/list/set/zset/hyperloglog)的操作 ,但在Java中我们通常以类对象为主,所以在Redis存储的数据结构月java对象之间进行转换,如自己编写一些工具类 比如一个角色对象的转换,还是比较容易的,但是涉及到许多对象的时候,这其中无论工作量还是工作难度都是很大的,所以总体来说, 就操作对象而言,使用Redis还是挺难的,好在spring对这些进行了封装和支持。
五、在spring中使用Redis
=================
上面说到了 Redis 无法操作对象的问题,无法在那些基础类型和 Java 对象之间方便的转换,但是在 Spring 中,这些问题都可以通过使用RedisTemplate得到解决!
想要达到这样的效果,除了 Jedis 包以外还需要在 Spring 引入 spring-data-redis 包。
1、使用spring配置JedisPoolConfig对象
大部分的情况下,我们还是会用到连接池的,于是先用 Spring 配置一个 JedisPoolConfig 对象:
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!--最大空闲数-->
<property name="maxIdle" value="50"/>
<!--最大连接数-->
<property name="maxTotal" value="100"/>
<!--最大等待时间-->
<property name="maxWaitMillis" value="20000"/>
</bean>
2、为连接池配置工厂模型
好了,我们现在配置好了连接池的相关属性,那么具体使用哪种工厂实现呢?在Spring Data Redis中有四种可供我们选择的工厂模型,它们分别是:
-
JredisConnectionFactory
-
JedisConnectionFactory
-
LettuceConnectionFactory
-
SrpConnectionFactory
我们这里就简单配置成JedisConnectionFactory:
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<!--Redis服务地址-->
<property name="hostName" value="localhost"/>
<!--端口号-->
<property name="port" value="6379"/>
<!--如果有密码则需要配置密码-->
<!--<property name="password" value="password"/>-->
<!--连接池配置-->
<property name="poolConfig" ref="poolConfig"/>
</bean>
3、配置RedisTemplate
普通的连接根本没有办法直接将对象直接存入 Redis 内存中,我们需要替代的方案:将对象序列化(可以简单的理解为继承Serializable接口)。我们可以把对象序列化之后存入Redis缓存中,然后在取出的时候又通过转换器,将序列化之后的对象反序列化回对象,这样就完成了我们的要求:
RedisTemplate可以帮助我们完成这份工作,它会找到对应的序列化器去转换Redis的键值:
<bean id="redisTemplate"
class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="connectionFactory"/>
4、测试
首先编写好支持我们测试的POJO类:
/**
* @author: 素小暖
* @create: 2020-2-12
*/
public class Student implements Serializable{
private String name;
private int age;
/**
* 给该类一个服务类用于测试
*/
public void service() {
System.out.println("学生名字为:" + name);
System.out.println("学生年龄为:" + age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
然后编写测试类:
@Test
public void test() {
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
RedisTemplate redisTemplate = context.getBean(RedisTemplate.class);
Student student = new Student();
## 总结
这个月马上就又要过去了,还在找工作的小伙伴要做好准备了,小编整理了大厂java程序员面试涉及到的绝大部分**面试题及答案**免费分享给大家,希望能帮助到大家,有需要的朋友可以看下面的**免费领取方式**!
> [资料领取方式:狂戳这里](https://gitee.com/vip204888/java-p7)
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/a3317115962bb5743608577585a769c9.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/520d167c917546b30f9703444602d8f6.png)
new ClassPathXmlApplicationContext("applicationContext.xml");
RedisTemplate redisTemplate = context.getBean(RedisTemplate.class);
Student student = new Student();
## 总结
这个月马上就又要过去了,还在找工作的小伙伴要做好准备了,小编整理了大厂java程序员面试涉及到的绝大部分**面试题及答案**免费分享给大家,希望能帮助到大家,有需要的朋友可以看下面的**免费领取方式**!
> [资料领取方式:狂戳这里](https://gitee.com/vip204888/java-p7)
[外链图片转存中...(img-ivhgUVwW-1628509134335)]
[外链图片转存中...(img-I6HtrK5e-1628509134337)]