什么是Redis
Redis 全称 Remote Dictionary Server(即远程字典服务),它是一个基于内存实现的键值型非关系(NoSQL)数据库,由意大利人 Salvatore Sanfilippo 使用 C 语言编写。Redis 遵守 BSD 协议,实现了免费开源,其最新版本是 6.20,常用版本包括 3.0 、4.0、5.0。自 Redis 诞生以来,它以其超高的性能、完美的文档和简洁易懂的源码广受好评,国内外很多大型互联网公司都在使用 Redis,比如腾讯、阿里、Twitter、Github 等等。
简单的来说:Redis是一种极其高效的,迅速的一种基于缓存读写的NoSQL(非关系型数据库,另一种解释是:不仅仅是数据库---Not Only a SQL)
Redis为什么这么快
1.Redis完全基于内存,众所周知,内存的读写速度要远远超过硬盘。
2.非阻塞IO
- 单线程,不存在加锁释放锁的操作,不存在死锁(但可以同时开启多个Redis来发挥多核的优势)
- 编码规范,代码优美高效
三个很流行的Redis的Java客户端
1.Jedis
2.SpringDataRedis
3.Redisson
4.Lettuce
.......
Jedis的介绍
Jedis是基于java语言的redis客户端,集成了redis的命令操作,同时提供了连接池管理。
Jedis的优点及缺点
Jedis集成了Redis的命令操作,他提供了比较全面的 Redis 操作特性的 API,同时他的最大的门槛是相对其他主流的Redis的Java客户端他的门槛较低,较简单。但值得一提的是,Jedis同步阻塞 IO,
,不支持异步,而且它本身是一种线程不安全的方式,为解决线程不安全的问题需要线程池来进行连接。
Jedis的导入
传统的jar包导入
传统的jar导入并不多赘述,也不推荐。
众所周知,传统Jar包的导入即去对应的网址下载所需的jar包,然后放在指定的目录的下,但这么做有很多的问题与缺点
统jar包导入的缺点
首先要去找到对应的官网下的对应版本的jar包,有时候还会在浏览器主页中遇到很多的广告的网址,要去做一个筛选判断,而且即便找到了对应好的所需jar包的官网,繁重的英文,大量的不知道干什么的文件......
而且即便是找到了正确的资源jar包,较慢的下载速度,较为繁琐的引入方式,让人很难受。
Maven项目管理引入Jedis
这里我们采用Maven项目管理的方式来完成jar包的引入,这里的另一个好处是,传统的项目的创建,比如idea的项目,在eclipse上未必能运行。而采用Maven项目管理的方式,也一定程度上提高了项目的兼容性。同时在Maven项目中的pom.xml中直接导坐标的形式,一定程度上非常非常非常方便。
创建Maven工程基础的教程这里就不多赘述了
pom.xml中的依赖如下:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
这里分别引入了测试和redis.clients的jedis的3.7.0版本
通过new的方式使用Jedis
package com;
import Tools.JedisConnectionFactory;
import redis.clients.jedis.Jedis;
import java.util.stream.StreamSupport;
public class JedisDemo {
private static Jedis jedis;
public static void connectJedis(){
jedis = new Jedis("127.0.0.1",6379);
// password
// select
jedis.select(0);
}
public static void run(){
String result = jedis.set("hobby","吃饭");
System.out.println("result = "+result);
String hobby = jedis.get("hobby");
System.out.println("hobby is "+hobby);
}
public static void end(){
if(jedis != null){
jedis.close();
}
}
public static void main(String[] args) {
connectJedis();
run();
end();
}
}
这里我们通过new Jedis(...)的方式完成Jedis的实例化。
如何我们分别定义了三个静态方法
- connectJedis()
- run()
- end()
分别是创立连接,执行命令和结束关闭销毁。
connectJedis()函数
new Jedis()中分别指定ip和端口
正常还需要在下一行提供密码,但是因为我们的redis没有设置密码,这里就不演示了。
run()函数
这里我们在run()函数中执行一些Redis的操作。
我们首先执行了set的操作
在redis中 set key value 可以向库中加入一个 键值对。
然后我们定义一个String result 来接收执行的结果。
然后我们下面又get了这个key(获取),
并通过 String hobby 来接受。
end()函数
在结束时,我们做了一个判断,如果jedis不为空(对象创立连接成功),就关闭销毁。
缺点
值得一提的是,Jedis本身是一种线程不安全的创建方式,这样做会导致线程不安全。
使用线程池建立连接
我们在java 目录下创立一个Tools目录,并创建一个 JedisConnectionFactory 类
代码如下:
package Tools;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisConnectionFactory {
private static final JedisPool jedisPool;
static {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 最大连接
jedisPoolConfig.setMaxTotal(8);
// 最大空闲连接
jedisPoolConfig.setMaxIdle(8);
// 最小空闲连接
jedisPoolConfig.setMinIdle(0);
// 设置最长等待时间
jedisPoolConfig.setMaxWaitMillis(200);
jedisPool = new JedisPool(jedisPoolConfig,"127.0.0.1",6379,1000);
}
public static Jedis getJedis() {
return jedisPool.getResource();
}
}
我们定义了一个JedisPool 类,然后在JedisConnectionFactory中写了一段静态方法(在类创建时执行一次且只执行一次)
最后写了一个getJedis()的方法用于对外通过反射连接到线程池中。
改变后的使用(JedisDemo)代码如下:
package com;
import Tools.JedisConnectionFactory;
import redis.clients.jedis.Jedis;
import java.util.stream.StreamSupport;
public class JedisDemo {
private static Jedis jedis;
public static void connectJedis(){
// jedis = new Jedis("127.0.0.1",6379);
jedis = JedisConnectionFactory.getJedis();
// password
// select
jedis.select(0);
}
public static void run(){
String result = jedis.set("hobby","吃饭");
System.out.println("result = "+result);
String hobby = jedis.get("hobby");
System.out.println("hobby is "+hobby);
}
public static void end(){
if(jedis != null){
jedis.close();
}
}
public static void main(String[] args) {
connectJedis();
run();
end();
}
}
可以看到,这里我们只是将原本的new 一个Jedis对象换成了通过我们封装在工具包下的工具类JedisConnectionFactory的类的getJedis()方法来以反射的形式创建这个Jedis对象。这样我们就解决了Jedis的线程不去安全的问题。
一个小项目的应用
看一个springboot中的应用,准备中正常创建静态代码块完成工厂,再通过反射获取Jedis实例,解决了线程连接不安全的问题,最后在接口中结合MySQL与Redis,完成查询的优化。
这里我们先在Redis中进行搜索,不存在的时候压力才会给到MySQL数据库,同时将结果一并存入Redis中,并设置过期时间,再次重复查询会直接通过Redis反馈结果。
@PostMapping("/JedisSelect")
@ResponseBody
public String JedisSelect(String name) {
System.out.println(name);
Jedis jedis = JedisConnectionFactory.getJedis();
Docter docter = new Docter();
String result = "";
if (jedis.get(name) != null) {
result = jedis.get(name);
}
else {
docter = daoMapper.SelectDocter(name);
if (docter != null) {
jedis.set(name,JSON.toJSONString(docter));
jedis.expire(name,1800);
}
result = JSON.toJSONString(docter);
}
if (jedis != null) {
jedis.close();
}
System.out.println(result);
return result;
}