• Redis


    1、Redis简介:

             Redis 是一个键值存储系统,支持多种数据结构,包括字符串(strings)、哈希(hash)、列表(lists)、集合(sets)和有序集合(sorted sets)等。它提供了丰富的命令集,可以对这些数据结构进行高效的读写操作。

            redis是一款高性能的NOSQL系类的非关系型数据库!

    Redis 主要有以下特点和用途:

    1. 内存存储:Redis 将数据存储在内存中,以实现高性能的读写操作。这使得它非常适合用作缓存层,可以大幅提高访问速度。

    2. 持久化支持:Redis 支持将数据持久化到磁盘,以便在重启后恢复数据。它提供了两种持久化方式:RDB(Redis Database)快照和 AOF(Append-Only File)日志。

    3. 高速数据访问:Redis 提供了快速的读取和写入操作,通常能在微秒级别内完成。这使得它在需要高速数据访问的场景下具有优势。

    4. 发布-订阅模式:Redis 支持发布-订阅模式,可以实现消息的发布和订阅功能。它可以用作简单的消息中间件,用于实时通信和事件驱动的架构。

    5. 分布式缓存:Redis 可以构建分布式缓存集群,将数据分布在多台机器上,以实现高可用性和横向扩展性。

    6. 数据结构支持:Redis 支持多种数据结构,如字符串、哈希、列表和集合等,使得它可以用于不同类型的应用场景,例如计数器、排行榜、会话管理等。目前支持的数据类型有字符串类型 string、哈希类型 hash、 列表类型 list、集合类型 set、有序集合类型 sortedset。

    2、NOSQL和关系型数据库比较:

    优点:
             1、成本:nosql数据库简单易部署,基本都是开源软件,不需要像使用oracle那样花费大量成本购买使用,相比关系型数据库价格便宜。
             2、查询速度:nosql数据库将数据存储于缓存之中,关系型数据库将数据存储在硬盘中,自然查询速度远不及nosql数据库。
            3、存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,所以可以存储基础类型以及对象或者是集合等各种格式,而数据库则只支持基础类型。

            4、扩展性:关系型数据库有类似join这样的多表查询机制的限制导致扩展很艰难。

    缺点:
            1、维护的工具和资料有限,因为nosql是属于新的技术,不能和关系型数据库10几年的技术同日而语。
            2、不提供对sql的支持,如果不支持sql这样的工业标准,将产生一定用户的学习和使用成本。
            3、不提供关系型数据库对事务的处理。

    非关系型数据库的优势:
            性能NOSQL是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过SQL层的解析,所以性能非常高。
            可扩展性同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展。

    关系型数据库的优势:
            复杂查询可以用SQL语句方便的在一个表以及多个表之间做非常复杂的数据查询。
            事务支持使得对于安全性能很高的数据访问要求得以实现。对于这两类数据库,对方的优势就是自己的弱势,反之亦然。 

    总结:

            关系型数据库与NoSQL数据库并非对立而是互补的关系,即通常情况下使用关系型数据库,在适合使用NoSQL的时候使用NoSQL数据库,让NoSQL数据库对关系型数据库的不足进行弥补。
    一般会将数据存储在关系型数据库中,在nosql数据库中备份存储关系型数据库的数据

     3、下载安装:

           这里说一下,由于有redis的官方并没有提供window版本的软件,官网上只能下在liunx版本的,但是在GitHub上有人提供啦window版本的Releases · microsoftarchive/redis (github.com)

    另外下载完,也不用安装直接解压就可以使用。

           
            * redis-server.exe:             redis服务器端       双击启动服务器端

           
            * redis-cli.exe:                    redis的客户端   双击启动客户端

                      * redis.windows.conf:        配置文件

    4、命令操作:

            数据存储的格式是  key,value ,其中key都是字符串,而value有五种数据结构

    字符串类型String
    哈希类型hash
    列表类型list
    集合类型set
    有序集合类型sortedset

           1、字符串类型

            存储: set    key  value

            获取: get    key

            删除: del    key

     2、哈希类型:

            存储: hset    key    filed     value

            获取指定的值: hget    key   filed

            获取所有的键和值:hgetall    key

            删除: hdel    key   filed

    3、列表数据类型:(很像队列)

           添加:

                    lpush    key   value    将数据添加到列表的左边

                    rpush    key   value    将数据添加到列表的右边

            获取:

                    范围获取: lrange   key    start    end

            删除:

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

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

    4、集合类型:(不允许有重复值)

            存储:  sadd  key  value    

                         sadd key  value1 value2.......

            获取:  smember   key    获取set列表的所有的元素

            删除:   srem  key  value   删除某个元素

                          srem   key  value1 value2.......

      5、有序集合类型:

            Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。

            存储:zadd   key   sorce   value

                      zadd   key   sorce   value1  value2    value3...

            获取:zrange    key   start    end

            获取指定范围的并且带分数:    zrange    key   start    end    withscores

            删除: zren   key   value

                        zren   key   value1     value2   value3

    6、通用命令:

           查询所有的键:

            keys  *

            查询键的类型:

            type  key

    5、数据持久化:

            Redis是一个内存数据库,当redis服务器重启或者电脑关机,数据就会丢失那么为了避免这种情况,我们可以将数据持久化,就是将Redis的数据写到硬盘中,这个过程就叫做持久化。

            持久化的方式有两种,一种是RDB(快照)一种是AOF(日志)

            1、RDB:

            RDB是redis的一种默认的持久化的方式,不需要额外的配置,就是在一定的时间的间隔内检测key的变化情况。然后去持久数据

            编辑  redis.window.conf  文件

                    #   after 900 sec (15 min) if at least 1 key changed
                    save 900 1
                    #   after 300 sec (5 min) if at least 10 keys changed
                    save 300 10
                    #   after 60 sec if at least 10000 keys changed
                    save 60 10000

             修改过后不能直接双击,应该在命令行窗口重启一下

            然后就可以打开了 

            如果只是学习,一般不做修改配置文件数据

           2、AOF:

            以日志的方式去记录数据进行数据的持久化,每一次命令操作后就会进行数据的持久化。AoF是将 redis 执行过的所有写指令记录下来,在下次 redis 重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。

            编辑配置文件

            因为AOF的配置文件时默认关闭的,要想使用的话要开启  

            1. 编辑redis.windwos.conf文件
                    appendonly no(关闭aof) --> appendonly yes (开启aof)


                    
                    # appendfsync always : 每一次操作都进行持久化
                    appendfsync everysec : 每隔一秒进行一次持久化
                    # appendfsync no     : 不进行持久化

            然后我们存储数据看看有没有生效!(这里直接重启就生成了配置文件,不用存数据)

     

            然后这里我为了和RDB做区别,就存储一个数据然后关闭服务器和客户端,接着重新启动后发现数据依然存在,说明我刚刚配置的生效啦

           

    3、两者对比:

    RDB持久化AOF持久化
    全量备份,一次保存整个数据库增量备份,一次只保存一个修改数据库的命令
    每次执行持久化操作的间隔时间较长保存的间隔默认为一秒钟(Everysec)
    数据保存为二进制格式,其还原速度快。使用文本格式还原数据,所以数据还原速度一般
    执行 SAVE 命令时会阻塞服务器,但手动或者自动触发的 BGSAVE 不会阻塞服务器 AOF持久化无论何时都不会阻塞服务器

    6、jedis:

            Jedis 是一个用于 Java 编程语言的 Redis 客户端库。它允许 Java 开发人员与 Redis 数据库进行交互,执行各种操作,如数据存储、检索、更新以及其他 Redis 支持的操作。

     Jedis 的主要特点:

    1. Redis 客户端库: Jedis 提供了一个 Java API,允许开发人员在 Java 应用程序中轻松地连接到 Redis 服务器并执行各种操作。

    2. 高性能: Jedis 被设计成高性能的 Redis 客户端,可以处理大量的请求和响应,并且提供了连接池的支持,以便有效地管理与 Redis 服务器的连接。

    3. 简单的 API: Jedis 提供了直观的 API,使得与 Redis 进行交互变得容易。例如,您可以使用 Jedis 将数据存储为字符串、哈希、列表等各种 Redis 数据结构。

    4. 连接池: Jedis 允许您创建连接池,以重复使用与 Redis 的连接,从而减少连接开销和提高性能。连接池还可以管理连接的生命周期,确保安全地打开和关闭连接。

    5. 支持发布-订阅模式: Jedis 支持 Redis 的发布-订阅功能,使您可以轻松实现消息传递和事件通知。

    6. 异常处理: Jedis 提供了异常处理机制,以处理与 Redis 服务器通信时可能出现的问题,如连接丢失、超时等。

    7. 集成性: Jedis 可以轻松地集成到 Java 应用程序中,无论是传统的 Java SE 应用程序还是 Java EE 应用程序,都可以使用 Jedis 来访问和操作 Redis 数据。

    1. package com.songzhishu.web.test;
    2. import org.junit.Test;
    3. import redis.clients.jedis.Jedis;
    4. import java.util.List;
    5. import java.util.Map;
    6. import java.util.Set;
    7. /**
    8. * @BelongsProject: web_tomcat
    9. * @BelongsPackage: com.songzhishu.web.test
    10. * @Author: 斗痘侠
    11. * @CreateTime: 2023-09-30 10:02
    12. * @Description: jedis的测试类
    13. * @Version: 1.0
    14. */
    15. public class JedisTest {
    16. @Test
    17. public void test1(){
    18. //获取连接
    19. Jedis jedis = new Jedis("localhost",6379);//也可以不写默认的就是本机端口号就是6379
    20. //操作
    21. jedis.set("username","张三");
    22. jedis.set("age","23");
    23. //关闭连接
    24. jedis.close();
    25. }
    26. //string
    27. @Test
    28. public void test2(){
    29. //链接
    30. Jedis jedis = new Jedis();
    31. //操作
    32. //存储
    33. jedis.set("username","zhangsan");
    34. //获取
    35. String usernaem = jedis.get("username");
    36. System.out.println(usernaem);
    37. //可以使用setex()的方法去存储指定过期时间的 key 和 value
    38. jedis.setex("activationCode",20,"hehe"); //将键和值存入redis,并且在20秒后自动删除键值对
    39. //关闭
    40. jedis.close();
    41. }
    42. //hash
    43. @Test
    44. public void test3(){
    45. //链接
    46. Jedis jedis = new Jedis();
    47. //操作
    48. jedis.hset("user","name","lisi");
    49. jedis.hset("user","gender","male");
    50. jedis.hset("user","age","24");
    51. //获取
    52. String name = jedis.hget("user", "name");
    53. String age = jedis.hget("user", "age");
    54. System.out.println(name+"="+age);
    55. //获取所有
    56. Map user = jedis.hgetAll("user");
    57. //遍历集合
    58. Set keySet = user.keySet();//获取key
    59. for (String key : keySet) {
    60. String value = user.get(key);
    61. System.out.println(key+"*"+value);
    62. }
    63. //关闭
    64. jedis.close();
    65. }
    66. //list
    67. @Test
    68. public void test4(){
    69. //链接
    70. Jedis jedis = new Jedis();
    71. //存储
    72. jedis.lpush("mylist","1","2","3","4");//4 3 2 1
    73. jedis.rpush("mylist","a","b","c","d");//4 3 2 1 a b c d
    74. //获取
    75. List mylist = jedis.lrange("mylist", 0, -1);//获取全部
    76. System.out.println(mylist);
    77. System.out.println("-------------------------");
    78. //遍历
    79. for (String value : mylist) {
    80. System.out.println(value);
    81. }
    82. System.out.println("---------------------");
    83. //左删除 弹出
    84. String mylist1 = jedis.lpop("mylist");//4
    85. System.out.println(mylist1);
    86. //右删除 弹出
    87. String mylsit2 = jedis.rpop("mylist");//d
    88. System.out.println(mylsit2);
    89. List list = jedis.lrange("mylist", 0, -1);
    90. System.out.println(list);
    91. //关闭
    92. jedis.close();
    93. }
    94. //set
    95. //set
    96. @Test
    97. public void test5(){
    98. //链接
    99. Jedis jedis = new Jedis();
    100. //存储
    101. jedis.sadd("myset","java","c","php","python");
    102. //获取
    103. Set myset = jedis.smembers("myset");
    104. System.out.println(myset);
    105. //关闭
    106. jedis.close();
    107. }
    108. //有序set
    109. @Test
    110. public void test6(){
    111. //链接
    112. Jedis jedis = new Jedis();
    113. //存储
    114. jedis.zadd("sortset",20,"A");
    115. jedis.zadd("sortset",1,"b");
    116. jedis.zadd("sortset",30,"c");
    117. jedis.zadd("sortset",15,"d");
    118. //获取
    119. Set sortset = jedis.zrange("sortset", 0, -1);
    120. System.out.println(sortset);
    121. //关闭
    122. jedis.close();
    123. }
    124. }

        连接池的配置参数: 

    1. #最大活动对象数
    2. redis.pool.maxTotal=1000
    3. #最大能够保持idel状态的对象数
    4. redis.pool.maxIdle=100
    5. #最小能够保持idel状态的对象数
    6. redis.pool.minIdle=50
    7. #当池内没有返回对象时,最大等待时间
    8. redis.pool.maxWaitMillis=10000
    9. #当调用borrow Object方法时,是否进行有效性检查
    10. redis.pool.testOnBorrow=true
    11. #当调用return Object方法时,是否进行有效性检查
    12. redis.pool.testOnReturn=true
    13. #“空闲链接”检测线程,检测的周期,毫秒数。如果为负值,表示不运行“检测线程”。默认为-1.
    14. redis.pool.timeBetweenEvictionRunsMillis=30000
    15. #向调用者输出“链接”对象时,是否检测它的空闲超时;
    16. redis.pool.testWhileIdle=true
    17. # 对于“空闲链接”检测线程而言,每次检测的链接资源的个数。默认为3.
    18. redis.pool.numTestsPerEvictionRun=50
    19. #redis服务器的IP
    20. redis.ip=xxxxxx
    21. #redis服务器的Port
    22. redis1.port=6379

    7、小案例:

            这里讲一下,使用redis缓存一部分不经常发生变化的数据,可以优化效率(就是避免从数据库中查询不变的数据的一种情况),一旦数据库中的数据发生了变化的话,那么就要更新缓存。

            前端:

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>省份案例title>
    6. <script src="../js/jquery-3.3.1.min.js">script>
    7. <script>
    8. $(function () {
    9. //页面加载完毕 返送ajax 获取省份
    10. $.get("/web_tomcat/FindProvinceServlet",{},function (data) {
    11. //将获取的数据填充到前端页面
    12. //获取select
    13. let province = $("#province");
    14. //遍历数组
    15. $(data).each(function () {
    16. //创建option
    17. var Option="+this.name+"";
    18. //调用append追加数据
    19. province.append(Option)
    20. })
    21. })
    22. })
    23. script>
    24. head>
    25. <body>
    26. <select id="province">
    27. <option>请选择省份option>
    28. select>
    29. body>
    30. html>

            select:

    1. package com.songzhishu.web.servlet;
    2. import com.songzhishu.web.service.ProvinceService;
    3. import com.songzhishu.web.service.impl.ProvinceServiceImpl;
    4. import javax.servlet.ServletException;
    5. import javax.servlet.annotation.WebServlet;
    6. import javax.servlet.http.HttpServlet;
    7. import javax.servlet.http.HttpServletRequest;
    8. import javax.servlet.http.HttpServletResponse;
    9. import java.io.IOException;
    10. /**
    11. * @BelongsProject: web_tomcat
    12. * @BelongsPackage: com.songzhishu.web.servlet
    13. * @Author: 斗痘侠
    14. * @CreateTime: 2023-09-30 14:20
    15. * @Description: TODO
    16. * @Version: 1.0
    17. */
    18. @WebServlet("/FindProvinceServlet")
    19. public class FindProvinceServlet extends HttpServlet {
    20. @Override
    21. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    22. this.doPost(req, resp);
    23. }
    24. @Override
    25. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    26. //设置响应的格式以及编码
    27. resp.setContentType("application/json;charset=utf-8");
    28. //调用service查询
    29. ProvinceService service = new ProvinceServiceImpl();
    30. /*//调用方法
    31. List list = service.findAll();
    32. //序列化
    33. ObjectMapper mapper = new ObjectMapper();
    34. String json = mapper.writeValueAsString(list);*/
    35. String json = service.findAllJson();
    36. System.out.println(json);
    37. //响应结果
    38. resp.getWriter().write(json);
    39. }
    40. }

             service:

            接口:

    1. package com.songzhishu.web.service;
    2. import com.songzhishu.web.domain.Province;
    3. import java.util.List;
    4. /**
    5. * @BelongsProject: web_tomcat
    6. * @BelongsPackage: com.songzhishu.web.service
    7. * @Author: 斗痘侠
    8. * @CreateTime: 2023-09-30 14:06
    9. * @Description: TODO
    10. * @Version: 1.0
    11. */
    12. public interface ProvinceService {
    13. List findAll();
    14. //从redis中读取数据
    15. String findAllJson();
    16. }

              实现类:

    1. package com.songzhishu.web.service.impl;
    2. import com.fasterxml.jackson.core.JsonProcessingException;
    3. import com.fasterxml.jackson.databind.ObjectMapper;
    4. import com.songzhishu.web.dao.ProvinceDao;
    5. import com.songzhishu.web.dao.impl.ProvinceDaoImpl;
    6. import com.songzhishu.web.domain.Province;
    7. import com.songzhishu.web.service.ProvinceService;
    8. import com.songzhishu.web.utils.JedisPoolUtils;
    9. import redis.clients.jedis.Jedis;
    10. import java.util.List;
    11. /**
    12. * @BelongsProject: web_tomcat
    13. * @BelongsPackage: com.songzhishu.web.service.impl
    14. * @Author: 斗痘侠
    15. * @CreateTime: 2023-09-30 14:09
    16. * @Description: TODO
    17. * @Version: 1.0
    18. */
    19. public class ProvinceServiceImpl implements ProvinceService {
    20. private ProvinceDao dao=new ProvinceDaoImpl();
    21. @Override
    22. public List findAll() {
    23. return dao.findAll();
    24. }
    25. //使用Redis的缓存
    26. @Override
    27. public String findAllJson() {
    28. //从redis中查询数据
    29. //创建redis连接
    30. Jedis jedis = JedisPoolUtils.getJedis();
    31. //获取数据 因为是字符串string get
    32. String province_json = jedis.get("province");
    33. //判断provinc是不是null
    34. if (province_json==null||province_json.length()==0){
    35. //说明没有数据 那么调用findAll
    36. List list = dao.findAll();
    37. //将集合序列化成json
    38. ObjectMapper mapper = new ObjectMapper();
    39. try {
    40. province_json = mapper.writeValueAsString(list);
    41. } catch (JsonProcessingException e) {
    42. e.printStackTrace();
    43. }
    44. //将查询到的数据存入redis
    45. jedis.set("province",province_json);
    46. jedis.close();
    47. System.out.println("缓存没有数据");
    48. }else {
    49. System.out.println("缓存有数据");
    50. }
    51. return province_json;
    52. }
    53. }

            dao:

            接口:

    1. package com.songzhishu.web.dao;
    2. import com.songzhishu.web.domain.Province;
    3. import java.util.List;
    4. public interface ProvinceDao {
    5. //查询所有
    6. public List findAll();
    7. }

            实现类:  

    1. package com.songzhishu.web.dao.impl;
    2. import com.songzhishu.web.dao.ProvinceDao;
    3. import com.songzhishu.web.domain.Province;
    4. import com.songzhishu.web.utils.JDBCUtils;
    5. import org.springframework.jdbc.core.BeanPropertyRowMapper;
    6. import org.springframework.jdbc.core.JdbcTemplate;
    7. import java.util.List;
    8. /**
    9. * @BelongsProject: web_tomcat
    10. * @BelongsPackage: com.songzhishu.web.dao.impl
    11. * @Author: 斗痘侠
    12. * @CreateTime: 2023-09-30 14:05
    13. * @Description: TODO
    14. * @Version: 1.0
    15. */
    16. public class ProvinceDaoImpl implements ProvinceDao {
    17. //声明成员变量 jdbcTemplement
    18. private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
    19. @Override
    20. public List findAll() {
    21. String sql="select * from province";
    22. List list = template.query(sql, new BeanPropertyRowMapper(Province.class));
    23. return list;
    24. }
    25. }

            domiain

    1. package com.songzhishu.web.domain;
    2. /**
    3. * @BelongsProject: web_tomcat
    4. * @BelongsPackage: com.songzhishu.web.domain
    5. * @Author: 斗痘侠
    6. * @CreateTime: 2023-09-30 13:55
    7. * @Description: TODO
    8. * @Version: 1.0
    9. */
    10. public class Province {
    11. private int id;
    12. private String name;
    13. public Province() {
    14. }
    15. public Province(int id, String name) {
    16. this.id = id;
    17. this.name = name;
    18. }
    19. /**
    20. * 获取
    21. * @return id
    22. */
    23. public int getId() {
    24. return id;
    25. }
    26. /**
    27. * 设置
    28. * @param id
    29. */
    30. public void setId(int id) {
    31. this.id = id;
    32. }
    33. /**
    34. * 获取
    35. * @return name
    36. */
    37. public String getName() {
    38. return name;
    39. }
    40. /**
    41. * 设置
    42. * @param name
    43. */
    44. public void setName(String name) {
    45. this.name = name;
    46. }
    47. public String toString() {
    48. return "Province{id = " + id + ", name = " + name + "}";
    49. }
    50. }

            数据库:

    1. CREATE TABLE province( -- 创建表
    2. id INT PRIMARY KEY AUTO_INCREMENT,
    3. NAME VARCHAR(20) NOT NULL
    4. );
    5. -- 插入数据
    6. INSERT INTO province VALUES(NULL,'北京');
    7. INSERT INTO province VALUES(NULL,'上海');
    8. INSERT INTO province VALUES(NULL,'广州');
    9. INSERT INTO province VALUES(NULL,'陕西');

  • 相关阅读:
    windows下git提交修改文件名大小写提交无效问题
    09.逻辑回归
    大数据ClickHouse(十三):MergeTree系列表引擎之VersionedCollapsingMergeTree
    浅析农场/农田区域入侵AI算法与视频监控技术的智慧农场解决方案
    HarmonyOS 音频开发指导:使用 AudioRenderer 开发音频播放功能
    超硬核!华为智慧屏上的家庭相册竟可以自动精准分类?
    【数据结构】优先级队列(堆)
    节点操作.
    Linux文件/目录高级管理二
    onnxruntime C++推理
  • 原文地址:https://blog.csdn.net/keleID/article/details/133419337