Redis【入门,Java面试手写算法

从上图我们可以知道以下两点:

  1. 第一次读取数据的时候,读取 Redis 的数据就会失败,此时就会触发程序读取数据库,把数据读取出来,并且写入 Redis 中;

  2. 第二次以及以后需要读取数据时,就会直接读取 Redis,读到数据后就结束了流程,这样速度就大大提高了。

从上面的分析可以知道,读操作的可能性是远大于写操作的,所以使用 Redis 来处理日常中需要经常读取的数据,速度提升是显而易见的,同时也降低了对数据库的依赖,使得数据库的压力大大减少。

分析了读操作的逻辑,下面我们来看看写操作的流程

从流程可以看出,更新或者写入的操作,需要多个 Redis 的操作,如果业务数据写次数远大于读次数那么就没有必要使用 Redis。

关于使用内存存储数据,我知道谷歌好像就是 把所有互联网的数据都存储在内存条的,所以才会有如此高质量、高效的搜索,但它毕竟是谷歌…

高速读/写的场合


在如今的互联网中,越来越多的存在高并发的情况,比如天猫双11、抢红包、抢演唱会门票等,这些场合都是在某一个瞬间或者是某一个短暂的时刻有成千上万的请求到达服务器,如果单纯的使用数据库来进行处理,就算不崩,也会很慢的,轻则造成用户体验极差用户量流失重则数据库瘫痪,服务宕机,而这样的场合都是不允许的!

所以我们需要使用 Redis 来应对这样的高并发需求的场合,我们先来看看一次请求操作的流程图

我们来进一步阐述这个过程:

  1. 当一个请求到达服务器时,只是把业务数据在 Redis 上进行读写,而没有对数据库进行任何的操作,这样就能大大提高读写的速度,从而满足高速响应的需求

  2. 但是这些缓存的数据仍然需要持久化,也就是存入数据库之中,所以在一个请求操作完 Redis 的读/写之后,会去判断该高速读/写的业务是否结束,这个判断通常会在秒杀商品为0,红包金额为0时成立,如果不成立,则不会操作数据库;如果成立,则触发事件将 Redis 的缓存的数据以批量的形式一次性写入数据库,从而完成持久化的工作。

Redis 的安装


访问地址:[https://github.com/ServiceStack/redis-windows/tree/master/downloads](

)

把 Redis 下载下来后找到一个合适的地方解压,就能得到如下图所示的目录(这里空格被替换成了%20…):

为了方便启动,我们在该目录下新建一个 startup.cmd 的文件,然后将以下内容写入文件:


redis-server redis.windows.conf 

这个命令其实就是在调用 redis-server.exe 命令来读取 redis.window.conf 的内容,我们双击刚才创建好的 startup.cmd 文件,就能成功的看到 Redis 启动:

上图的提示信息告诉了我们:① Redis 当前的版本为 3.0.503;**② Redis 运行在 6379 端口;**③ Redis 进程的 PID 为 14748;④ 64 位。

我们可以打开同一个文件夹下的 redis-cli.exe 文件,这是 Redis 自带的一个客户端工具,它可以用来连接到我们当前的 Redis 服务器,我们做以下测试:

如此,我们便在 Windows 的环境下安装好了 Redis。


在 Java 中使用 Redis


第一步:添加 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次 

据说 Redis 的性能能达到十万级别,我不敢相信我的台式机电脑只有十分之一不到的性能,虽然说这里不是流水线的操作,会造成一定的影响,但我还是不信邪,我查到了官方的性能测试方法:

**首先在Redis根目录下召唤Cmd:**具体方法是按住【Shift】点击右键

**然后输入命令:【redis-benchmark -n 100000 -q】:**来同时执行10万个请求测试性能

好吧,我同时在我的笔记本上测试了一下,结果更加惨淡…low啊low…

第二步:使用 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 包:[https://mvnrepository.com/artifact/org.springframework.data/spring-data-redis](

)

这里把2.0.7最新版本标红的意思是:别老想着使用最新的Jar包,特别是涉及到框架的一些东西,笔者用实际的操作体验告诉你们,引入该版本的包是会导致Jar包冲突的(也就是莫名其妙的错误),我乖乖换回了1.7.2的版本,代码就通了…我们来看看怎么做吧:

(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"/> 

笔者从《JavaEE互联网轻量级框架整合开发》中了解到,这一步需要配置单独的序列化器去支撑这一步的工作,但是自己在测试当中,发现只要我们的POJO类实现了Serializable接口,就不会出现问题…所以我直接省略掉了配置序列化器这一步…

(4)第四步:编写测试

首先编写好支持我们测试的POJO类:


/**

 * @author: @我没有三颗心脏

 * @create: 2018-05-30-下午 22:31

 */

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);


# 最后

我想问下大家当初选择做程序员的初衷是什么?有思考过这个问题吗?高薪?热爱?

既然入了这行就应该知道,这个行业是靠本事吃饭的,你想要拿高薪没有问题,请好好磨练自己的技术,不要抱怨。有的人通过培训可以让自己成长,有些人可以通过自律强大的自学能力成长,如果你两者都不占,还怎么拿高薪?

架构师是很多程序员的职业目标,一个好的架构师是不愁所谓的35岁高龄门槛的,到了那个时候,照样大把的企业挖他。为什么很多人想进阿里巴巴,无非不是福利待遇好以及优质的人脉资源,这对个人职业发展是有非常大帮助的。

如果你也想成为一名好的架构师,那或许这份**Java核心架构笔记**你需要阅读阅读,希望能够对你的职业发展有所帮助。

**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](

)**

**中高级开发必知必会:**

plicationContext("applicationContext.xml");

	RedisTemplate redisTemplate = context.getBean(RedisTemplate.class);


# 最后

我想问下大家当初选择做程序员的初衷是什么?有思考过这个问题吗?高薪?热爱?

既然入了这行就应该知道,这个行业是靠本事吃饭的,你想要拿高薪没有问题,请好好磨练自己的技术,不要抱怨。有的人通过培训可以让自己成长,有些人可以通过自律强大的自学能力成长,如果你两者都不占,还怎么拿高薪?

架构师是很多程序员的职业目标,一个好的架构师是不愁所谓的35岁高龄门槛的,到了那个时候,照样大把的企业挖他。为什么很多人想进阿里巴巴,无非不是福利待遇好以及优质的人脉资源,这对个人职业发展是有非常大帮助的。

如果你也想成为一名好的架构师,那或许这份**Java核心架构笔记**你需要阅读阅读,希望能够对你的职业发展有所帮助。

**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](

)**

**中高级开发必知必会:**

![](https://img-blog.csdnimg.cn/img_convert/039a1385e628ae04216c9d1df73d1863.png)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值