Redis学习笔记

  概念

Redis是一款高性能的NOSQL系列的非关系型数据库。

关系型数据库:例如MySQL,数据之间有关联关系,数据存储在硬盘文件上(操作耗时)。

非关系型数据库:存储键值对,数据直接无关联,数据存储在内存中(缓存思想)。

缓存:常用于查询一些不太经常发生变化的数据。

我们优先从缓存中获取数据,若缓存中已经存在我们所需要的数据,就可直接返回。

若缓存中不存在我们需要的数据,就去数据库中查询,然后将数据放入缓存,最后返回数据。

关系型数据库与NOSQL数据库并非对立,而是互补的关系。一般将数据寸尺在关系型数据库中,在NOSQL数据库中进行备份。

Redis是用C语言开发的一个开源的高性能键值对数据库。应用于缓存,消息队列(解决秒杀项目高并发问题)等。

 

  Redis下载

中文官网

下载完成后,解压即可。

关注3个文件:

redis.windows.conf:配置文件

redis-server.exe:服务器端执行文件

redis-cli.exe:客户端端执行文件

首先我们打开服务器端,默认运行在6379端口。不要关闭服务器端,我们打开客户端,输入命令set name zhangsan,页面显示OK,这样我们就存入了一个键值对。再次输入命令get name,页面显示“zhangsan”,这样就读取到了刚刚存入的数据。

 使用Redis的两种方式:命令,或Java代码(Jedis)。

 

  Redis数据结构

redis存储键值对(相当于一个大map),key的类型必须为字符串,value可以为5种数据结构,下面分别介绍:

1.字符串类型:最普通的类型,没啥好介绍的

2.哈希类型hash:相当于Java中的map格式。也就是说,value也是一个键值对的形式。

3.列表类型list:相当于Java中的linkedlist格式。列表格式,有序,可以重复。

4.集合类型set:相当于Java中的set类型。列表格式,无序,不可重复。

5.有序集合类型sortedset:列表格式,有序,不可重复。

 

  命令操作

1.字符串类型

存储:set key value

获取value值:get key

删除:del key

2.哈希类型

存储:hset key field value

获取:hget key field或hgetall key(获取所有的filed和value)

删除:hdel key field

  3.列表类型

这里的列表是一个左右两端均开放的“队列”,可以添加到列表的头部(左边)或尾部(右边)。

允许重复元素。

存储:lpush key value 将元素加入列表最左边,rpush key value 将元素加入列表最右边

获取:lrange key start end:返回获取,获取全部时为lrange key 0 -1

删除:lpop key:删除列表最左边的元素,并将其返回,rpop key:删除列表最右边的元素,并将其返回

 4.集合类型

不允许重复元素。且存入的value没有顺序。

存储:saad key value

获取所有元素:smembers key 

删除:srem key value

 5.有序集合类型

不允许重复元素,且元素有顺序。

存储:zaad key score value

按score升序排列

获取:zrange key start end

删除:zrem key value

 6.通用命令

查询所有的键:keys *

查询指定key的类型:type key

删除指定的键值对:del key

 

  持久化

redis是一个内存数据库,当redis重启,或者电脑重启,数据就会丢失,我们可以将redis内存中的数据持久化保存到硬盘的文件中。

redis有两种持久化机制:

1.RDB:默认方式。在一定的间隔时间中,检测key变化情况,然后持久化数据

查看配置文件,找到如下三行:

 这三行的意思是:如果900秒内有1个key值被改动,就持久化一次。如果300秒内有10个key值被改动,就持久化一次。如果60秒内有10000个key值被改动,就持久化一次。

若改动了配置文件,就不能直接打开服务器和客户端使用redis。

我们需要在cmd中输入:redis-server.exe redis.windows.conf来手动启动服务器,然后再打开客户端,输入命令。持久化后,目录下会生成一个后缀为rdb的文件,用来存储持久化的数据。

 2.AOF:日志记录的方式,可以记录每一条命令的操作。每一次命令操作后,都持久化一次数据。

在配置文件中找到这一行,把no改为yes,就表示使用AOF持久化方式。

 开启AOF后,可以继续指定如下的配置:

 第一行表示,每次操作都进行持久化。第二行表示,每隔1秒进行一次持久化(默认)。第三行表示,不进行持久化。

我们需要在cmd中输入:redis-server.exe redis.windows.conf来手动启动服务器,然后再打开客户端,输入命令。持久化后,目录下会生成一个后缀为aof的文件,用来存储持久化的数据。

 

  Java客户端——Jedis

一款Java操作redis数据库的工具。

使用步骤:在project structure中导入两个jar包

 然后进行如下入门操作:

1     @Test
2     public void test1(){
3         //获取连接
4         Jedis jedis = new Jedis("localhost",6379);
5         //操作
6         jedis.set("score","100");
7         //关闭连接
8         jedis.close();
9     }

运行后,使用key *命令,可以看到score已经被创建。

Jedis中的方法名称与命令相同,因此理解上较为简单,下面直接给出一些代码来演示:

 1.操作String

 1     @Test
 2     public void test1(){
 3         //获取连接
 4         Jedis jedis = new Jedis("localhost",6379);
 5         //操作
 6         jedis.set("score","100");
 7         String score = jedis.get("score");
 8         System.out.println(score);
 9         //20秒后自动删除该键值对
10         jedis.setex("activecode",20,"60");
11         //关闭连接
12         jedis.close();
13     }

setex()方法表示存储键值对activecode-60,20秒后自动删除,可以应用于存储一些有时效的验证码/激活码等。

注意:redis无论value是什么数据类型,但其中最后的数据类型都是String,所以activecode和60都要用双引号括起来

2.操作hash

 1 @Test
 2     public void test2(){
 3         //获取连接
 4         Jedis jedis = new Jedis("localhost",6379);
 5         //操作
 6         //存储hash
 7         jedis.hset("user","name","Lisa");
 8         jedis.hset("user","age","24");
 9         jedis.hset("user","sex","female");
10         //获取hash
11         Map<String,String> user = jedis.hgetAll("user");
12         //遍历打印user中存储的键值对
13         Set<String> keySet = user.keySet();
14         for(String key:keySet){
15             String value = user.get(key);
16             System.out.println(key + ":" + value);
17         }
18         //关闭连接
19         jedis.close();
20     }

运行后打印结果:

 3.操作列表类型

 1 @Test
 2     public void test3(){
 3         //获取连接
 4         Jedis jedis = new Jedis("localhost",6379);
 5         //操作
 6         //存储
 7         jedis.lpush("mylist","a","b","c");
 8         jedis.rpush("mylist","d","e","f");
 9         //获取
10         List<String> mylist = jedis.lrange("mylist",0,-1);
11         System.out.println(mylist);
12         //弹出
13         String element1 = jedis.lpop("mylist");
14         System.out.println(element1);
15         String element2 = jedis.rpop("mylist");
16         System.out.println(element2);
17         //获取
18         List<String> newmylist = jedis.lrange("mylist",0,-1);
19         System.out.println(newmylist);
20         //关闭连接
21         jedis.close();
22     }

运行后打印结果:

 4.存储集合

 1     @Test
 2     public void test4(){
 3         //获取连接
 4         Jedis jedis = new Jedis("localhost",6379);
 5         //操作
 6         //存储
 7         jedis.sadd("mySet","java","php","c++");
 8         //获取
 9         Set<String> mySet = jedis.smembers("mySet");
10         System.out.println(mySet);
11         //关闭连接
12         jedis.close();
13     }

运行后打印结果:(注意是无序的)

 5.操作有序集合

 1 @Test
 2     public void test5(){
 3         //获取连接
 4         Jedis jedis = new Jedis("localhost",6379);
 5         //操作
 6         //存储
 7         jedis.zadd("mySortedSet",10,"鲁班大师");
 8         jedis.zadd("mySortedSet",30,"杨玉环");
 9         jedis.zadd("mySortedSet",40,"盾山");
10         //获取
11         Set<String> mySortedSet = jedis.zrange("mySortedSet",0,-1);
12         System.out.println(mySortedSet);
13         //关闭连接
14         jedis.close();
15     }

运行后打印结果:(按照score值升序排列)

 

  Jedis连接池:JedisPool

使用:

1.创建JedisPool连接池对象

2.调用方法getResource()方法获取Jedis连接

 1     @Test
 2     public void testJedisPool(){
 3         //创建配置对象
 4         JedisPoolConfig config = new JedisPoolConfig();
 5         config.setMaxTotal(50);//允许最多连接数
 6         config.setMaxIdle(10);//允许最大空闲连接
 7         //创建连接池对象
 8         JedisPool jedisPool = new JedisPool(config,"localhost",6379);
 9         //获取连接
10         Jedis jedis = jedisPool.getResource();
11         //使用
12         jedis.set("counts","20");
13         //关闭,归还到连接池中
14         jedis.close();
15     }

当然,也可以直接修改配置文件,然后创建连接池对象时,使用默认参数。

常用配置:

 

  连接池工具类的编写与应用

工具类编写:

 1 public class JedisPoolUtils {
 2     private static JedisPool jedisPool;
 3     static{
 4         //读取配置文件
 5         InputStream is = JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
 6         //创建Properties对象
 7         Properties pro = new Properties();
 8         //关联文件
 9         try {
10             pro.load(is);
11         } catch (IOException e) {
12             e.printStackTrace();
13         }
14         //获取数据,设置到JedisPoolConfig中
15         JedisPoolConfig config = new JedisPoolConfig();
16         config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
17         config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));
18         //初始化JedisPool
19         jedisPool = new JedisPool(config,pro.getProperty("host"),Integer.parseInt(pro.getProperty("port")));
20     }
21 
22     //获取连接方法
23     public static Jedis getJedis(){
24         return jedisPool.getResource();
25     }
26 }

应用:

1     @Test
2     public void testJedisUtils(){
3         //通过连接池工具了获取
4         Jedis jedis = JedisPoolUtils.getJedis();
5         //操作
6         jedis.set("Name","Lily");
7         //关闭,归还到连接池中
8         jedis.close();
9     }

 注意:jedis.properties要放到jedis包下,与utils包,test包平行,才能被读取到。

 

  Redis案例

案例需求:

1. 提供index.html页面,页面中有一个省份 下拉列表
2. 当 页面加载完成后 发送ajax请求,加载所有省份

步骤1:创建MySQL数据库表格

  步骤2:环境搭建

导入相应jar包,web中导入js目录。

 导入druid配置文件。

1 driverClassName=com.mysql.jdbc.Driver
2 url=jdbc:mysql:///jedis
3 username=root
4 password=0322
5 initialSize=5
6 maxActive=10
7 maxWait=3000

 步骤3:3层架构代码编写

domain

 1 public class Province {
 2     private int id;
 3     private String name;
 4 
 5     public int getId() {
 6         return id;
 7     }
 8 
 9     public void setId(int id) {
10         this.id = id;
11     }
12 
13     public String getName() {
14         return name;
15     }
16 
17     public void setName(String name) {
18         this.name = name;
19     }
20 }
domain

dao接口

1 public interface ProvinceDao {
2     public List<Province> findAll();
3 }
dao接口

daoImpl实现

 1 public class ProvinceDaoImpl implements ProvinceDao {
 2     //声明成员变量
 3     private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
 4     @Override
 5     public List<Province> findAll() {
 6         //定义sql
 7         String sql = "select * from province";
 8         //执行sql
 9         List<Province> list = template.query(sql, new BeanPropertyRowMapper<Province>(Province.class));
10         return list;
11     }
12 }
DaoImpl

service接口

1 public interface ProvinceService {
2     public List<Province> findAll();
3 }
View Code

serviceImpl实现

1 public class ProvinceServiceImpl implements ProvinceService {
2     //声明dao
3     private ProvinceDao dao = new ProvinceDaoImpl();
4 
5     @Override
6     public List<Province> findAll() {
7         return dao.findAll();
8     }
9 }
serviceImpl

ProvinceServet

 1 @WebServlet(name = "provinceServlet")
 2 public class ProvinceServlet extends HttpServlet {
 3     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 4         //调用service查询
 5         ProvinceService service = new ProvinceServiceImpl();
 6         List<Province> list = service.findAll();
 7         //序列化list为json
 8         ObjectMapper mapper = new ObjectMapper();
 9         String json = mapper.writeValueAsString(list);
10         System.out.println(json);
11         //响应结果
12         response.setContentType("application/json;charset=utf-8");
13         response.getWriter().write(json);
14 
15     }
16 
17     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
18 
19     }
20 }
ProvinceServlet

index.html

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <script src="js/jquery-3.3.1.min.js"></script>
 7     <script>
 8             $(function(){
 9                   //发送ajax请求,加载所有省份数据
10                 $.get("provinceServlet",{},function (data) {
11                     //获取select
12                     var province = $("#province");
13                     //遍历json数组
14                     $(data).each(function(){
15                         //创建<option>
16                         var option = "<option name='"+this.id+"'>"+this.name+"</option>>";
17                         //调用select的append追加option
18                         province.append(option);
19 
20                         });
21 
22 
23                 });
24             });
25     </script>
26 
27 </head>
28 <body>
29 <select id="province">
30         <option>--请选择省份--</option>
31 </select>
32 
33 </body>
index

步骤4:加入redis,实现缓存优化

在service接口中添加一个方法

public String findAllJson();

serviceImpl中重写该方法,实现缓存操作:

 1     @Override
 2     public String findAllJson() {
 3         //1.先从redis中查询数据
 4         //1.1获取redis客户端连接
 5         Jedis jedis = JedisPoolUtils.getJedis();
 6         String province_json = jedis.get("province");
 7 
 8         //2判断 province_json 数据是否为null
 9         if(province_json == null || province_json.length() == 0){
10             //redis中没有数据
11             System.out.println("redis中没数据,查询数据库...");
12             //2.1从数据中查询
13             List<Province> ps = dao.findAll();
14             //2.2将list序列化为json
15             ObjectMapper mapper = new ObjectMapper();
16             try {
17                 province_json = mapper.writeValueAsString(ps);
18             } catch (JsonProcessingException e) {
19                 e.printStackTrace();
20             }
21 
22             //2.3 将json数据存入redis
23             jedis.set("province",province_json);
24             //归还连接
25             jedis.close();
26 
27         }else{
28             System.out.println("redis中有数据,查询缓存...");
29         }
30 
31         return province_json;
32     }

 但是,一旦数据改变,就需要更新缓存。

添加redis缓存后,第一次读取数据需要访问mysql,然后数据就会缓存在redis中,下一次读取时,直接从缓存中读取即可。

 

posted @ 2020-06-07 00:38  菅兮徽音  阅读(123)  评论(0编辑  收藏  举报