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_第1张图片

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

Redis_第2张图片

                  * redis.windows.conf:        配置文件

4、命令操作:

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

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

       1、字符串类型

        存储: set    key  value

        获取: get    key

        删除: del    key

Redis_第3张图片

 2、哈希类型:

        存储: hset    key    filed     value

        获取指定的值: hget    key   filed

        获取所有的键和值:hgetall    key

        删除: hdel    key   filed

Redis_第4张图片

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

       添加:

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

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

        获取:

                范围获取: lrange   key    start    end

        删除:

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

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

Redis_第5张图片

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

        存储:  sadd  key  value    

                     sadd key  value1 value2.......

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

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

                      srem   key  value1 value2.......

Redis_第6张图片

  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

Redis_第7张图片

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

Redis_第8张图片

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

Redis_第9张图片

        然后就可以打开了 

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

       2、AOF:

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

        编辑配置文件

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

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

Redis_第10张图片
                
                # appendfsync always : 每一次操作都进行持久化
                appendfsync everysec : 每隔一秒进行一次持久化
                # appendfsync no     : 不进行持久化

Redis_第11张图片

Redis_第12张图片

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

 Redis_第13张图片

        然后这里我为了和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 数据。

package com.songzhishu.web.test;

import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @BelongsProject: web_tomcat
 * @BelongsPackage: com.songzhishu.web.test
 * @Author: 斗痘侠
 * @CreateTime: 2023-09-30  10:02
 * @Description: jedis的测试类
 * @Version: 1.0
 */
public class JedisTest {

    @Test
    public  void  test1(){
        //获取连接
        Jedis jedis = new Jedis("localhost",6379);//也可以不写默认的就是本机端口号就是6379
        //操作
        jedis.set("username","张三");
        jedis.set("age","23");
        //关闭连接
        jedis.close();
    }

    //string
    @Test
    public void test2(){
        //链接
        Jedis jedis = new Jedis();
        //操作

        //存储
        jedis.set("username","zhangsan");

        //获取
        String usernaem = jedis.get("username");
        System.out.println(usernaem);

        //可以使用setex()的方法去存储指定过期时间的 key 和 value
        jedis.setex("activationCode",20,"hehe"); //将键和值存入redis,并且在20秒后自动删除键值对

        //关闭
        jedis.close();
    }


    //hash
    @Test
    public void test3(){
        //链接
        Jedis jedis = new Jedis();
        //操作
        jedis.hset("user","name","lisi");
        jedis.hset("user","gender","male");
        jedis.hset("user","age","24");

        //获取
        String name = jedis.hget("user", "name");
        String age = jedis.hget("user", "age");
        System.out.println(name+"="+age);


        //获取所有
        Map user = jedis.hgetAll("user");
        //遍历集合
        Set keySet = user.keySet();//获取key
        for (String key : keySet) {
            String value = user.get(key);
            System.out.println(key+"*"+value);
        }
        //关闭
        jedis.close();
    }

    //list
    @Test
    public void test4(){
        //链接
        Jedis jedis = new Jedis();

        //存储
        jedis.lpush("mylist","1","2","3","4");//4 3 2 1
        jedis.rpush("mylist","a","b","c","d");//4 3 2 1 a b c d


        //获取
        List mylist = jedis.lrange("mylist", 0, -1);//获取全部

        System.out.println(mylist);
        System.out.println("-------------------------");
        //遍历
        for (String value : mylist) {
            System.out.println(value);
        }
        System.out.println("---------------------");
        //左删除 弹出
        String mylist1 = jedis.lpop("mylist");//4
        System.out.println(mylist1);
        //右删除 弹出
        String mylsit2 = jedis.rpop("mylist");//d
        System.out.println(mylsit2);

        List list = jedis.lrange("mylist", 0, -1);
        System.out.println(list);


        //关闭
        jedis.close();
    }

    //set
    //set
    @Test
    public void test5(){
        //链接
        Jedis jedis = new Jedis();

        //存储
        jedis.sadd("myset","java","c","php","python");

        //获取
        Set myset = jedis.smembers("myset");
        System.out.println(myset);

        //关闭
        jedis.close();
    }

    //有序set
    @Test
    public void test6(){
        //链接
        Jedis jedis = new Jedis();

        //存储
        jedis.zadd("sortset",20,"A");
        jedis.zadd("sortset",1,"b");
        jedis.zadd("sortset",30,"c");
        jedis.zadd("sortset",15,"d");

        //获取
        Set sortset = jedis.zrange("sortset", 0, -1);
        System.out.println(sortset);


        //关闭
        jedis.close();
    }

}

    连接池的配置参数: 

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

7、小案例:

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

        前端:




    
    省份案例
  
  




        select:

package com.songzhishu.web.servlet;

import com.songzhishu.web.service.ProvinceService;
import com.songzhishu.web.service.impl.ProvinceServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @BelongsProject: web_tomcat
 * @BelongsPackage: com.songzhishu.web.servlet
 * @Author: 斗痘侠
 * @CreateTime: 2023-09-30  14:20
 * @Description: TODO
 * @Version: 1.0
 */
@WebServlet("/FindProvinceServlet")
public class FindProvinceServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置响应的格式以及编码
        resp.setContentType("application/json;charset=utf-8");

        //调用service查询
        ProvinceService service = new ProvinceServiceImpl();

        /*//调用方法
        List list = service.findAll();

        //序列化
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(list);*/


        String json = service.findAllJson();
        System.out.println(json);
        //响应结果
        resp.getWriter().write(json);

    }
}

         service:

        接口:

package com.songzhishu.web.service;

import com.songzhishu.web.domain.Province;

import java.util.List;

/**
 * @BelongsProject: web_tomcat
 * @BelongsPackage: com.songzhishu.web.service
 * @Author: 斗痘侠
 * @CreateTime: 2023-09-30  14:06
 * @Description: TODO
 * @Version: 1.0
 */
public interface ProvinceService {
    List findAll();

    //从redis中读取数据
    String findAllJson();
}

          实现类:

package com.songzhishu.web.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.songzhishu.web.dao.ProvinceDao;
import com.songzhishu.web.dao.impl.ProvinceDaoImpl;
import com.songzhishu.web.domain.Province;
import com.songzhishu.web.service.ProvinceService;
import com.songzhishu.web.utils.JedisPoolUtils;
import redis.clients.jedis.Jedis;

import java.util.List;

/**
 * @BelongsProject: web_tomcat
 * @BelongsPackage: com.songzhishu.web.service.impl
 * @Author: 斗痘侠
 * @CreateTime: 2023-09-30  14:09
 * @Description: TODO
 * @Version: 1.0
 */
public class ProvinceServiceImpl implements ProvinceService {


    private ProvinceDao dao=new ProvinceDaoImpl();
    @Override
    public List findAll() {
        return dao.findAll();
    }

    //使用Redis的缓存
    @Override
    public String findAllJson() {
        //从redis中查询数据

        //创建redis连接
        Jedis jedis = JedisPoolUtils.getJedis();

        //获取数据 因为是字符串string get
        String province_json = jedis.get("province");

        //判断provinc是不是null
        if (province_json==null||province_json.length()==0){
            //说明没有数据 那么调用findAll
            List list = dao.findAll();

            //将集合序列化成json
            ObjectMapper mapper = new ObjectMapper();
            try {
                 province_json = mapper.writeValueAsString(list);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            //将查询到的数据存入redis
            jedis.set("province",province_json);
            jedis.close();
            System.out.println("缓存没有数据");
        }else {
            System.out.println("缓存有数据");
        }

        return province_json;
    }
}

        dao:

        接口:

package com.songzhishu.web.dao;

import com.songzhishu.web.domain.Province;

import java.util.List;

public interface ProvinceDao {
    //查询所有
    public List findAll();
}

        实现类:  

package com.songzhishu.web.dao.impl;

import com.songzhishu.web.dao.ProvinceDao;
import com.songzhishu.web.domain.Province;
import com.songzhishu.web.utils.JDBCUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.List;

/**
 * @BelongsProject: web_tomcat
 * @BelongsPackage: com.songzhishu.web.dao.impl
 * @Author: 斗痘侠
 * @CreateTime: 2023-09-30  14:05
 * @Description: TODO
 * @Version: 1.0
 */
public class ProvinceDaoImpl implements ProvinceDao {
    //声明成员变量 jdbcTemplement
    private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
    @Override
    public List findAll() {
        String sql="select * from province";
        List list = template.query(sql, new BeanPropertyRowMapper(Province.class));
        return list;
    }
}

        domiain

package com.songzhishu.web.domain;

/**
 * @BelongsProject: web_tomcat
 * @BelongsPackage: com.songzhishu.web.domain
 * @Author: 斗痘侠
 * @CreateTime: 2023-09-30  13:55
 * @Description: TODO
 * @Version: 1.0
 */
public class Province {
    private int id;
    private String name;


    public Province() {
    }

    public Province(int id, String name) {
        this.id = id;
        this.name = name;
    }

    /**
     * 获取
     * @return id
     */
    public int getId() {
        return id;
    }

    /**
     * 设置
     * @param id
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    public String toString() {
        return "Province{id = " + id + ", name = " + name + "}";
    }
}

        数据库:

CREATE TABLE province(   -- 创建表
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20) NOT NULL
	
);
-- 插入数据
INSERT INTO province VALUES(NULL,'北京');
INSERT INTO province VALUES(NULL,'上海');
INSERT INTO province VALUES(NULL,'广州');
INSERT INTO province VALUES(NULL,'陕西');

你可能感兴趣的:(Redis,redis,数据库,缓存)