1-概念

  • redis是一款高性能的NoSQL系列的非关系型数据库
  • redis做缓存数据

    1.1-非关系型数据库

    • 数据之间没有关联关系
    • 数据存储在内存中
    • 速度快
    • 关系型数据库和nosql数据库互补
    • 数据存储在关系型数据库中,在nosql中备份

      1.2-缓存思想

  • 查询一些不太发生变化的数据

    • 从缓存中获取数据
      • 有数据
        • 直接返回
      • 没有数据
        • 从数据库中查询
        • 将数据放入缓存
        • 返回数据

          2-下载安装

  • 官网:https://redis.io

  • 中文网:https://www.redis.net.cn
  • 在终端进入下载后的目录,然后:
    • 解压:tar zxvf redis-5.0.5.tar.gz
    • 移动到:sudo mv redis-5.0.5 /usr/local
    • 切换到:cd /usr/local/redis-5.0.5/
    • 编译测试:make test
    • 编译安装:make install
  • 运行

    • 终端 redis-server
    • 新建终端窗口 redis-cli

      3-命令操作

      3.1-Redis数据结构

  • redis存储的是:key,value格式的数据,其中key都是字符串,value有5中不同的数据结构

  • value数据结构:
    • 字符串 string
    • 哈希 hash : map格式
    • 列表类型 list
    • 集合类型 set
    • 有序集合类型 sortedset
  • 字符串类型 string
    • 存储: set key value
    • 获取: get key
    • 删除: del key
  • 哈希 hash
    • 存储: hset key field value
    • 获取:
      • hget key field 获取指定field对应值
      • hgetall key 获取所有field和value
    • 删除: hdel key field
  • 列表类型 list :可以添加元素到列表头部(左)或尾部(右)
    • 添加
      • lpush key value : 将元素加入列表左侧 left
      • rpush key value : 将元素加入列表右侧 right
    • 获取
      • lrange key start end : 范围获取
    • 删除
      • lpop key:删除列表最左边元素,并返回
      • rpop key:删除列表最右边元素,并返回
  • 集合类型 set:不允许重复
    • 存储:sadd key value
    • 获取:smembers key:获取set集合中所有元素
    • 删除:srem key value:删除set集合中的某个元素
  • 有序集合 sortedset:不允许重复

    • 存储:zadd key score value:根据score分数从小到大排序
    • 获取:zrange key start end
    • 删除:zrem key value

      3.2-通用命令

  • keys * : 查询所有的键

  • type key:获取对应键的类型
  • del key:删除指定键

    4-持久化操作

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

    4.1-持久化机制

    4.1.1-RDB

  • 默认方式,不需要进行配置,默认就使用这种机制

    • 在一定的间隔时间中,检测key的变化情况,然后持久化数据
    • 编辑redis.conf文件
      • save 900 1 #900秒(15分钟)如有一个key发生改变,则持久化一次
      • save 300 10 #300秒(5分钟) 10个key改变,则持久化一次
      • save 60 10000 #60秒 10000个key ->持久化
    • 重新启动redis,并指定配置文件名称

      4.1.2-AOF

  • 日志记录的方式,可以记录每一条命令的操作。在每一次命令操作后,持久化数据

    • 编辑redis.conf文件
      • appendonly no(关闭AOF) —> appendonly yes(开启AOF)
      • appendfsync always : 每一次操作都进行持久化(默认被注释)

      • appendfsync everysec :每隔一秒进行一次持久化(默认)
      • appendfsync no :不进行持久化(默认被注释)

5-Java操作Redis

5.1-Jedis

  • 一款java操作redis数据库的工具,类似JDBC

    5.1.1-使用步骤

    • 下载jedis的jar包
    • 使用
      1. //获取连接
      2. Jedis jedis = new Jedis("localhost",6379);
      3. //操作
      4. jedis.set("username","zhangsan");
      5. //关闭连接
      6. jedis.close();

      5.1.2-Jedis操作各种redis数据结构

  • 字符串 string: set/get

    1. //存储
    2. jedis.set("username","zhangsan");
    3. //获取
    4. String username = jedis.get("username");
    5. System.out.println(username);
    6. //可以使用setex()方法存储可以指定过期时间的 key value
    7. jedis.setex("activecode",20,"haha");
    8. //将activecode:haha存入redis,并且20秒后自动删除
  • 哈希 hash : map格式 :hset/hget/hgetAll

    1. //存储hash
    2. jedis.hset("user","name","lisi");
    3. jedis.hset("user","age","23");
    4. jedis.hset("user","gender","male");
    5. //获取hash
    6. String name = jedis.hget("user", "name");
    7. System.out.println(name);
    8. //获取所有
    9. Map<String,String> map = jedis.hgetAll("user");
    10. //keyset
    11. Set<String> strings = map.keySet();
    12. for (String key : strings) {
    13. String s = map.get(key);
    14. System.out.println(key+":"+s);
    15. }
  • 列表类型 list : lpush/rpush lpop/rpop

    1. //操作
    2. //jedis.lpush("mylist","a","b","c");//left
    3. //jedis.rpush("mylist","a","b","c");//right
    4. List<String> mylist = jedis.lrange("mylist", 0, -1);
    5. System.out.println(mylist);
    6. String element = jedis.lpop("mylist");//弹出
    7. System.out.println(element);
    8. List<String> mylist1 = jedis.lrange("mylist", 0, -1);
    9. System.out.println(mylist1);
  • 集合类型 set : sadd/smembers/srem ```java //操作

      jedis.sadd("myset","a","b","c");//存入
      Set<String> myset = jedis.smembers("myset");//获取
      System.out.println(myset);
      jedis.srem("myset","a");
      Set<String> myset1 = jedis.smembers("myset");
      System.out.println(myset1);
    

- 有序集合类型 sortedset : zadd/zrem/zrange
```java
 //存入
        jedis.zadd("mysort",100,"roderick");
        jedis.zadd("mysort",28,"people");
        jedis.zadd("mysort",80,"own");

        Set<String> mysort = jedis.zrange("mysort", 0, -1);
        System.out.println(mysort);

        jedis.zrem("mysort", "own");//删除

        Set<String> mysort1 = jedis.zrange("mysort", 0, -1);
        System.out.println(mysort1);

5.1.3-Jedis连接池:JedisPool

  • 使用

    • 创建JedisPool连接池对象
    • 调用方法 getResource()方法获取Jedis连接

      5.1.4-JedisPoolUtils

      ```java /**

      • JedisPool工具类
      • 加载配置文件:配置连接池参数
      • 提供获取连接的方法 */ public class JedisPoolUtils {

      private static JedisPool jedisPool;

static{
    //读取配置文件
    InputStream is = JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
    //创建Properties对象
    Properties pro = new Properties();
    //关联文件
    try {
        pro.load(is);
    } catch (IOException e) {
        e.printStackTrace();
    }
    //获取数据,设置到JedisPoolConfig中
    JedisPoolConfig config = new JedisPoolConfig();
    config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal"))); //需要int型的参数所以使用parseInt转换
    config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));

    //初始化JedisPool
    jedisPool = new JedisPool(config,pro.getProperty("host"),Integer.parseInt(pro.getProperty("port")));
}
/**
 * 获取连接的方法
 */
public static Jedis getJedis(){
    return jedisPool.getResource();
}

}


<a name="vyOOr"></a>
## 6-案例
<a name="ZqVBd"></a>
### 6.1-案例需求

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

![截屏2021-01-19 13.53.41.png](https://cdn.nlark.com/yuque/0/2021/png/1238354/1611035657720-a9dbf7be-bc6a-405c-8e25-418fc6531e51.png#crop=0&crop=0&crop=1&crop=1&height=612&id=snRlf&margin=%5Bobject%20Object%5D&name=%E6%88%AA%E5%B1%8F2021-01-19%2013.53.41.png&originHeight=612&originWidth=1640&originalType=binary&ratio=1&rotation=0&showTitle=false&size=144960&status=done&style=none&title=&width=1640)
<a name="e5cnJ"></a>
### 6.2-Redis缓存优化
![截屏2021-01-19 13.56.35.png](https://cdn.nlark.com/yuque/0/2021/png/1238354/1611035828597-5b39e40f-f86a-412a-a513-a1058934a9ac.png#crop=0&crop=0&crop=1&crop=1&height=728&id=hd82P&margin=%5Bobject%20Object%5D&name=%E6%88%AA%E5%B1%8F2021-01-19%2013.56.35.png&originHeight=728&originWidth=1640&originalType=binary&ratio=1&rotation=0&showTitle=false&size=248675&status=done&style=none&title=&width=1640)
```java
/**
     * 使用redis缓存
     */
    @Override
    public String findAllJson() {
        //1-先从redis中查询数据
        //1-1-获取redis客户端连接
        Jedis jedis = JedisPoolUtils.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> ps = dao.findAll();
            //2.2-将list序列化为json
            ObjectMapper mapper = new ObjectMapper();
            try {
                province_json = mapper.writeValueAsString(ps);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            //2.3-将数据存入redis缓存
            jedis.set("province",province_json);
            //归还连接(try..catch..finally)
            jedis.close();
        }else{
            System.out.println("redis缓存中有数据,查询缓存");
        }
        return province_json;
    }

6.3-注意

  • 使用Redis缓存一些不经常发生变化的数据
  • 数据库的数据一旦发生改变,则需要更新缓存
    • 数据库的表执行 增删改的相关操作,需要将redis缓存数据清空,再次存入
    • 在service对应的 增删改方法中,将redis数据删除