Redis笔记

概念

  1. Redis 是一个开源,高级的键值存储和一个适用的解决方案,用于构建高性能,可扩展的 Web 应用程序。
  2. 内存nosql数据库。
  3. 号称10W+的QPS;
  4. 多用于缓存,内存中读取,速度快。
  5. Redis 支持分布式锁、事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。
  6. 对比关系型数据库:
    在这里插入图片描述

下载安装

安装redis和redis Desktop Manager.
再Win下(可以使用多个cmd窗口进行服务端和客户端的启动):
- redis.windoes.conf :配置文件
- redis-server.exe : redis服务器
- redis-cli : redis的客户端

命令操作

redis的数据结构

redis存储的是key-value格式的数据,key是字符串,value有5种不同的数据结构
value的数据结构

数据类型说明
String字符串
hash哈希(map格式)
list列表(LinkedList,可重复)
set集合(hashset,不可重复)
zset有序集合(sortedset,不重复可自排序)

在这里插入图片描述

上述图片中,list、set、zset三种类型都是一样的存储结构。
元素上,list允许元素重复;set和zset不允许元素重复;
有序方面,list和set无序;zset会排序

redis命令操作(参照中文网文档)

redis教程
Redis命令文档(可直接查询)

String

  1. 存储
redis> SET mykey "Hello"
OK

返回值
integer-reply:含义如下
--1如果field是一个新的字段
--0如果field原来在map里面已经存在
  1. 获取
redis> GET mykey
"Hello"

返回值
integer-reply:含义如下
--1如果field是一个新的字段
--0如果field原来在map里面已经存在
  1. 删除
redis> SET key1 "Hello"
OK
redis> SET key2 "World"
OK
redis> DEL key1 key2 key3
(integer) 2

返回值
integer-reply: 被删除的keys的数量

hash

  1. 存储
redis> HSET myhash field1 "Hello"
(integer) 1
hget key field : 获取field对应的值
hgetall key :获取所有的field和value

返回值
integer-reply:含义如下
--1如果field是一个新的字段
--0如果field原来在map里面已经存在
  1. 获取
redis> HGET myhash field1
"Hello"

返回值
integer-reply:含义如下
--1如果field是一个新的字段
--0如果field原来在map里面已经存在
  1. 删除
redis> HSET myhash field1 "foo"
(integer) 1
redis> HDEL myhash field1
(integer) 1
redis> HDEL myhash field2
(integer) 0

从 key 指定的哈希集中移除指定的域。在哈希集中不存在的域将被忽略。如果 key 指定的哈希集不存在,
它将被认为是一个空的哈希集,该命令将返回0。

返回值
integer-reply: 返回从哈希集中成功移除的域的数量,不包括指出但不存在的那些域
历史:在 2.4及以上版本中 :可接受多个域作为参数。小于 2.4版本 的 Redis 每次调用只能移除一个域
 要在早期版本中以原子方式从哈希集中移除多个域,可用 MULTI/EXEC块。

list

  1. 添加
    可以添加一个元素导列表的头部(左边 lpush )或者尾部(右边 rpush
//将元素插入链表左边
lpush key value 
//将元素插入链表右边
rpush key value 
  1. 获取
//范围获取
lrange key start end
  1. 删除
//删除列表最左边元素,并将元素返回
lpop key
//删除列表最右边元素,并将元素返回
rpop key

set(存取不保证顺序)

  1. 添加
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SADD myset "World"
(integer) 0
redis> SMEMBERS myset
1) "World"
2) "Hello"

integer-reply:
返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素.

历史
= 2.4: 接受多个member 参数. Redis 2.4 以前的版本每次只能添加一个member元素.
  1. 获取
//获取全部 smember
redis> SMEMBERS myset
1) "World"
2) "Hello"

返回值
array-reply:集合中的所有元素.
  1. 删除
redis> SADD myset "one"
(integer) 1
redis> SADD myset "two"
(integer) 1
redis> SADD myset "three"
(integer) 1
redis> SREM myset "one"
(integer) 1
redis> SREM myset "four"
(integer) 0
redis> SMEMBERS myset
1) "three"
2) "two"

在key集合中移除指定的元素. 如果指定的元素不是key集合中的元素则忽略 如果key集合不存在则
被视为一个空的集合,该命令返回0.如果key的类型不是一个集合,则返回错误.

返回值
integer-reply:从集合中移除元素的个数,不包括不存在的成员.

历史
= 2.4: 接受多个 member 元素参数. Redis 2.4 之前的版本每次只能移除一个元素.

zset(sorted set有序集合)

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

  1. 添加
//会按照score对value进行排序
zadd key score value
将所有指定成员添加到键为key有序集合(sorted set)里面。 添加时可以指定多个分数/成员(score/member)
对。 
如果指定添加的成员已经是有序集合里面的成员,则会更新改成员的分数(scrore)并更新到正确的排序位置。
如果key不存在,将会创建一个新的有序集合(sorted set)并将分数/成员(score/member)对添加到有序集合,
就像原来存在一个空的有序集合一样。
如果key存在,但是类型不是有序集合,将会返回一个错误应答。

分数值是一个双精度的浮点型数字字符串。+inf和-inf都是有效值。
  1. 获取
//范围获取
zrange key start end

redis 127.0.0.1:6379> ZADD w3ckey 1 redis
(integer) 1
redis 127.0.0.1:6379> ZADD w3ckey 2 mongodb
(integer) 1
redis 127.0.0.1:6379> ZADD w3ckey 3 mysql
(integer) 1
redis 127.0.0.1:6379> ZADD w3ckey 3 mysql
(integer) 0
redis 127.0.0.1:6379> ZADD w3ckey 4 mysql
(integer) 0
redis 127.0.0.1:6379> ZRANGE w3ckey 0 10 WITHSCORES
 //withScores 可以连分数score一起获取
1) "redis"
2) "1"
3) "mongodb"
4) "2"
5) "mysql"
6) "4"
  1. 删除
zrem key value

通用命令

//查询所有的键。*可以匹配正则表达式
  keys *
 //查看键对应的value的类型(以名为“username”的key为例)
  type username
  //删除制定的key value
   del key

持久化操作

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

redis持久化机制

RDB

  • 默认方式,不需配置,默认此种机制

  • 在一定的间隔时间中,检测Key的变化情况,然后持久化数据;

    • 编辑redis.windows.conf文件(以下为第98行左右配置及其注解)

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

    save 900 1 #15分钟后有至少一个key改变就持久化一次
    save 300 10 #5分钟后有至少10个key改变就持久化一次
    save 60 10000 #60秒后有至少10000个key改变就持久化一次

AOF

  • 日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据。
  • 通过编辑redis.windows.conf文件实现
    • 581行===appendonly no 参数改为yes,默认AOF是关闭的(no)
    • 三个参数:

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

使用Java客户端操作Redis–>Jedis

Jedis

定义:是java操作Redis数据库的工具。
使用步骤:

  1. 下载jedis的jar包
  2. 使用

对jedis在java程序中进行实操,实现对String、hash、list、sorted set的操作
以Spring Boot项目为例,需要使用到的有关redis的依赖有

<!-- Redis依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
			<!--            <version>2.1.3.RELEASE</version>-->
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-pool2</artifactId>
			<version>2.5.0</version>
		</dependency>

		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>3.3.0</version>
		</dependency>

简单入门操作

简单的操作:

  1. 获取连接
  2. 操作
  3. 关闭连接

实现如下:

package com.example.demo.jedis;

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


/**
 * Jedis 测试类
 */
public class JedisTest {
    /**
     * 快速入门
     * redis通过客户端使用,只需要三步操作即可
     */
    @Test
    public void test1(){
        //1.获取连接
        Jedis jedis = new Jedis("localhost",6379);
        //2、操作
        jedis.set("username","goldfish124");
        //3.关闭连接
        jedis.close();
    }
}

jedis操作五种数据结构

代码使用方法和命令行客户端使用的方法方法名是一致的。
方法是嵌入上述结构的,代码实现:

	/**
     * 字符串数据结构的操作
     * 运行结果:
     * --------------------------
     * goldfish124
     * --------------------------
     */
    @Test
    public void test2(){
        //1.获取连接
        //这里的连接如果不写参数,默认值就是"localhost"和6379,分别ip和端口
        Jedis jedis = new Jedis("localhost",6379);
        //2、操作
        //2.1 存储数据
        jedis.set("username","goldfish124");
        //2.2 取出参数
        String username = jedis.get("username");
        System.out.println(username);
        //3.关闭连接
        jedis.close();
    }
 /**
     * hash哈希数据结构操作
     * 运行结果:
     * --------------------------
     * goldfish124
	 * gender--保密
  	 * age--22
	 * username--goldfish124
     * --------------------------
     */

    @Test
    public void test3(){
        //1.获取连接
        //这里的连接如果不写参数,默认值就是"localhost"和6379,分别ip和端口
        Jedis jedis = new Jedis("localhost",6379);
        //2、操作
        //2.1 存储hash数据
        // 如果是相同的key反复存储,后面存储的value会覆盖前面的
        jedis.hset("myhash","username","goldfish124");
        jedis.hset("myhash","age","22");
        jedis.hset("myhash","gender","保密");
        //2.2 获取hash
        String username = jedis.hget("myhash","username");
        System.out.println(username);
        //2.3 获取hash中所有map的数据
        Map<String,String> user = jedis.hgetAll("myhash");
        //keyset方式获取集合
        Set<String>  keyset = user.keySet();
        for (String key : keyset) {
            //获取value
            String value = user.get(key);
            System.out.println(key + "--"+value);

        }

        //3.关闭连接
        jedis.close();
    }
	
	/**
     * list 列表数据结构操作
     * 最终运行结果:
     * --------------------------
     * [d, l, o, g, g, o, l, d]
     * pop1 = d
     * pop2 = d
     * [l, o, g, g, o, l]
     * --------------------------
     */
    @Test
    public void test4(){
        //1.获取连接
        //这里的连接如果不写参数,默认值就是"localhost"和6379,分别ip和端口
        Jedis jedis = new Jedis("localhost",6379);
        //2、操作
        //2.1 list的存储
        //左边存
        jedis.lpush("mylist","g","o","l","d");
        //右边存
        jedis.rpush("mylist","g","o","l","d");
        //存储结果为:[d, l, o, g, g, o, l, d]
        //2.2 获取list中数据
        //范围获取获取所有(0,-1)
        List<String> mylist1 = jedis.lrange("mylist",0,-1);
        System.out.println(mylist1);

        //2.3 list弹出
        String pop1 = jedis.lpop("mylist");
        System.out.println("pop1 = "+ pop1);//g

        String pop2 = jedis.rpop("mylist");
        System.out.println("pop2 = " + pop2);//g
        //2.4 获取弹出后的list中数据
        List<String> mylist2 = jedis.lrange("mylist",0,-1);
        System.out.println(mylist2);
        //3.关闭连接
        jedis.close();
    }
	
	/**
     * set列表数据结构操作
     * 最终运行结果:
     * 存取不保证顺序,所以有以下结果
     * --------------------------
     * [goldfish, java, love]
     * --------------------------
     */
    @Test
    public void test5(){
        //1.获取连接
        //这里的连接如果不写参数,默认值就是"localhost"和6379,分别ip和端口
        Jedis jedis = new Jedis("localhost",6379);
        //2、操作
        // set存储
        jedis.sadd("myset","goldfish","love","java");

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

        //3.关闭连接
        jedis.close();
    }

	 /**
     * sortedset列表数据结构操作
     * 最终运行结果:
     * score 的值改变,元素的顺序也会发生改变
     * --------------------------
     * [钟无艳, 大乔, 小乔]
     * --------------------------
     */
    @Test
    public void test6(){
        //1.获取连接
        //这里的连接如果不写参数,默认值就是"localhost"和6379,分别ip和端口
        Jedis jedis = new Jedis("localhost",6379);
        //2、操作
        //sortedset 存储
        //score 的值改变,元素的顺序也会发生改变
        jedis.zadd("mysortedset",3,"钟无艳");
        jedis.zadd("mysortedset",30,"大乔");
        jedis.zadd("mysortedset",60,"小乔");

        //sortedset 获取
        Set<String> mysortedset = jedis.zrange("mysortedset",0,-1);
        System.out.println(mysortedset);

        //3.关闭连接
        jedis.close();
    }

Jedis连接池

使用

  1. 创建JedisPool连接池对象
  2. 调用方法 getResource() 方法获取redis连接
/**
     * jedis连接池的使用
     */
    @Test
    public void test7(){
        //0.创建一个配置对象
        //对连接池的相关属性进行配置
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(50);
        config.setMaxIdle(10);

        //1.创建jedis连接池对象
        //没有参数的时候是默认配置,根据需要再对配置进行修改
        JedisPool jedisPool = new JedisPool("localhost",6379);

        //2.获取连接
        Jedis jedis = jedisPool.getResource();

        //3.使用,通过如上四种操作不同数据类型的方法进行使用
        //对jedis的操作
        jedis.set("name","goldfish111");

        //4.关闭jedis对象,使资源归还到连接池中
        jedis.close();
    }

连接池配置参数详解

#最大活动对象数
redis.pool.maxTotle=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.testWhileIdel=true
#对于“空闲链接”检测线程而言,每次检测的链接资源个数,默认为3
redis.pool.numTestsPerEvictionRun=50
#redis服务器的IP
redis.ip=XXXX
#redis服务器的port
redis.port=6379

抽取成连接池工具类

工具类为 JedisPoolUtil 类:

package com.example.demo.jedis;


import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * JedisPool工具类
 * 加载配置文件
 * 提供获取连接的方法
 */
public class JedisPoolUtil {

  private static JedisPool jedisPool;

  static{
    //读取配置文件
    //jedisPool配置文件jedis.properties内容
    //----------------------
    //host=127.0.0.1
    //port=6379
    //maxTotal=50
    //maxIdle=10
    //----------------------
    // 可在相应目录文件添加需要加载的jedisPool配置文件
    InputStream is = JedisUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
    //创建Properties对象
    Properties pro = new Properties();
    //关联文件并抛出相应的异常
    try {
      pro.load(is);
    } catch (IOException e) {
      e.printStackTrace();
    }
    //获取数据,设置到JedisPoolConfig中
    JedisPoolConfig config = new JedisPoolConfig();
    //这里pro拿到的是字符串,setMaxTotal方法的参数是int,需要将数值装换成int
    config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
    config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));

    //初始化JedisPool对象
    //端口号要转成数字
    jedisPool = new JedisPool(config,pro.getProperty("host"),
        Integer.parseInt(pro.getProperty("port")));
  }

  /**
   * 获取连接的方法
   * @return
   */
  public static Jedis getJedis(){
    return jedisPool.getResource();
  }
  // TODO 还可以书写其他的公用方法,关闭方法等
}

测试工具类方法:

	/**
     * jedis连接池工具类的使用
     */
    @Test
    public void test8(){
        //通过连接池工具类获取jedis
        Jedis jedis = JedisUtils.getJedis();

        //使用,通过如上四种操作不同数据类型的方法进行使用
        //对jedis的操作
        jedis.set("name","goldfish222");

        //关闭jedis对象,使资源归还到连接池中
        jedis.close();
    }

在Spring Boot的yml配置文件中可以进行如下数据库配置(可替代工具类中的静态代码块的引入配置):

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver #数据库连接驱动
    name: demo01
    url: jdbc:mysql://localhost:3306/XXX
    username: XXX
    password: XXX
  redis: ### Redis Configuration
    jedis:
      pool:
        max-idle: 10
        min-idle: 5
        max-totle: 20
    hostName: 127.0.0.1
    port: 6379

redis案例实现

案例需求

后端实现功能:
查询一个选择省份的下拉框里面所有备选项的数据库内容。先从redis缓存中查询数据,如果缓存中没有数据,就在数据库中查询,存到redis中,再返回数据。如果缓存中有数据,则直接返回数据。

实现

主要实现部分(JedisServiceImpl ):

package com.example.demo.jedis;

import com.example.demo.dao.JedisTestDao;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import redis.clients.jedis.Jedis;

public class JedisServiceImpl implements JedisServive {
  @Autowired
  JedisTestDao jedisTestDao;

  @Override
  public List<Province> findAll() {
    return jedisTestDao.findAllProvince();
  }

  /**
   *使用数据库缓存
   * @return
   */
  @Override
  public String findAllJson() {
    //1. 先从redis中查询数据
    //1.1 获取redis客户端连接--jedis
//    Jedis jedis = new Jedis();
    //也可以通过刚才的数据库连接池工具类获取连接
    Jedis jedis = JedisUtils.getJedis();
    String province_json = jedis.get("province");
    
    //2.判断province_json是否为null
    if (province_json == null || province_json.length() == 0){
      //redis中没有数据
      System.out.println("redis中无数据,查询数据库=======");
      //2.1 从数据库中查询
      List<Province> provinceList=jedisTestDao.findAllProvince();
      //2.2 将list序列化为json
      ObjectMapper mapper = new ObjectMapper();
      try {
        province_json = mapper.writeValueAsString(provinceList);
      } catch (JsonProcessingException e) {
        e.printStackTrace();
      }
      
      //2.3 将json数据存入redis中,set方法
      jedis.set("province",province_json);
      //归还连接
      jedis.close();
    }else{
      //测试,看是否有数据,是否正确
      System.out.println("redis中有数据,查询缓存=========");
    }
    return province_json;
  }
}

还有service的接口类,我是用的SpringBoot项目,使用Mybits对数据库进行相应的相应的查询语句的书写。

注意 !!!

在分布式使用redis存储值的时候,必须设置失效时间,没有失效时间的键值对会在缓存中占用空间!
在缓存空间中,当缓存满了需要清理的时候,有失效时间的键值对会被优先淘汰掉,而没有失效时间的键值对如果不会被用到就会很占用空间,同时也会降低存储反应效率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值