SpringBoot学习(七)—— springboot快速整合Redis
Redis缓存
@
简介
redis是一个高性能的key-value数据库
优势
性能强,适合高度的读写操作(读的速度是110000次/s,写的速度是81000次/s )。
支持较为丰富的数据类型(如二进制的Strings, Lists, Hashes, Sets ,Ordered Sets)
一定的事物能力(要么执行成功要么完全不执行)。
劣势
- 内存数据库访问快,但也消耗硬件内存资源
 
注:redis的单线程仅仅是说在网络请求这一模块上用一个请求处理客户端的请求,但比如说持久化它就会重开一个线程/进程去进行处理。
引入redis缓存
点击链接 下载 redis 的 window 版,下载好后,放入你平时放软件的位置,解压出来即安装完成。(需要注意的是放入的文件目录,当前用户要是可读可写的权限,比如window下的C:\Program Files (x86),这个目录默认只有管理员权限才能读写,redis运行时要在该目录下实时写入日志文件的,若无权限读写,则会操作不成功)

解压出来的目录如下所示,因为是Windows端的,可双击exe文件开启客户端,服务端。

因为这是 springboot 整合 redis 系列,所以双击打开服务端即可,别关闭打开的 cmd 窗口。

在pom.xml中加入
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在application.properties中添加
# Redis
#Redis服务器地址
spring.redis.host=127.0.0.1
#Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
#Redis数据库索引(默认为0)
spring.redis.database=0
#连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=50
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=3000
#连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=20
#连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=5
#连接超时时间(毫秒)
spring.redis.timeout=4000
代码实战
新增代码后的目录如下所示

这里先说明一下主要类的作用,Springboot 提供了 RedisTemplate 类来操作 Redis,但是该类既无注释解释,命名规律也不够 “望文生义” 。 所以写了个 RedisUtil 来封装一些常用的方法, RedisConfig 主要是将默认的自动注入改为手动注入并加入序列化,避免一些中文乱码问题。
这里特别说一说 RedisUtil 类,搜索 springboot 和 redis 的文章,这个需要自己封装的类网上大多写的非常混乱,而且前后的封装逻辑不一致, 我估计是某位博主从至少三个人那里复制粘贴糅合起来的,然后大家都跟着这位博主复制粘贴,反而成了热门文章。我猜测大家看它是个工具类,而且六百行左右,大多没有仔细琢磨,能简单测试通过即可,但是稍加思考,发现问题真的不少,很容易误导那些喜欢 “拿来主义” 的 “萌新” 。
虽然我这个系列也是快速上手系列,但我理解的快速上手,就是把让人云里雾里的概念讲直白,然后先暂时跳过那些需要深入的,避免刚入手的畏难情绪,把整个操作流程写的清楚明白,给别人讲一千遍道一万句,不如让他对着现成的程序跑一遍,我一直认为:对着一片空白的屏幕学习程序,只会让人愈加焦虑,最好的办法是一边运行,一边深入。
所以我选取了 redis 五大类型中的String,Hash,Set,List,几乎覆盖每个类型,而 SortedSet 没有选取是因为这是有序的Set,可以自己类比。工具类我统一提供的是取值,添加值,删除值,命名规律绝对可以让你 “望文生义” ,其实还有很多方法,这里我不全写出来,是因为五大数据类型都有一堆方法,你不一定用得上,而且很占篇幅,在这里,授人以鱼不如授人以渔,你仔细看看 RedisUtil 的工具类,就会发现规律,比如操作String,大多是先调用opsForValue()方法,操作Hash,大多先调用opsForHash()方法,把项目源码下载到本地,idea里面点进去,就能看到相关的一堆方法。工具类只是重新调用了,换了个名字,加了些逻辑处理。
别看是热门文章就盲从,我举几个刚才说的问题,


还有这个的注释说明风格也不统一,给人的感觉看着容易云里雾里的,网上的工具类还用的都是这一个,真的是哭笑不得,大家抄来抄去,都是方案整合商,就不要……
下面开始代码示范
RedisController.java
package com.example.controller;
import com.example.service.IRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("redis")
public class RedisController {
    @Autowired
    private IRedisService redisService;
    @RequestMapping("/redisString")
    public void redisString() {
        this.redisService.redisString();
    }
    @RequestMapping("/redisHash")
    public void redisHash() {
        this.redisService.redisHash();
    }
    @RequestMapping("/redisSet")
    public void redisSet() {
        this.redisService.redisSet();
    }
    @RequestMapping("/redisList")
    public void redisList() {
        this.redisService.redisList();
    }
    @RequestMapping("/redisSortedSet")
    public void redisSortedSet() {
        //有序的set,故而省略
    }
}
IRedisService.java
package com.example.service;
public interface IRedisService {
    void redisString();
    void redisHash();
    void redisSet();
    void redisList();
    void redisSortedSet();
}
RedisServiceIml.java
package com.example.service;
import com.example.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
@Service("redisService")
public class RedisServiceIml implements IRedisService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private RedisUtil redisUtil;
    public void redisString() {
        //添加值
        redisUtil.stringSet("AAA", "这是一个String类型的值");
        //取值
        Object value = redisUtil.stringGet("AAA");
        System.out.println(value);
    }
    public void redisHash() {
        //添加值
        redisUtil.hashSet("BBB", "test1", "原hash值1");
        redisUtil.hashSet("BBB", "test2", "新hash值1");
        redisUtil.hashSet("BBB", "test1", "原hash值2");
        redisUtil.hashSet("BBB", "test2", "新hash值2");
        //取值
        Object value1 = redisUtil.hashGet("BBB", "test1");
        Object value2 = redisUtil.hashGet("BBB", "test2");
        System.out.println(value1);
        System.out.println(value2);
    }
    public void redisSet() {
        //添值
        redisUtil.setSet("CCC", "这是一组Set集合的第一个");
        redisUtil.setSet("CCC", "这是一组Set集合的第二个");
        redisUtil.setSet("CCC", "这是一组Set集合的第三个");
        //取值
        Set vaule = redisUtil.setGet("CCC");
        System.out.println(vaule);
    }
    public void redisList() {
        //添加值
        redisUtil.listSet("DDD", "这是一组List集合的第一个");
        redisUtil.listSet("DDD", "这是一组List集合的第二个");
        redisUtil.listSet("DDD", "这是一组List集合的第三个");
        //取值
        List list = redisUtil.listGet("DDD", 0, -1);
        System.out.println(list);
    }
    public void redisSortedSet() {
        //有序的set,故而省略
    }
}
RedisConfig.java
package com.example.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置连接工厂
        template.setConnectionFactory(factory);
        //序列化和反序列化redis中的值
        Jackson2JsonRedisSerializer jackson = new Jackson2JsonRedisSerializer(Object.class);
        //Java对象转换成JSON结构
        ObjectMapper objectMapper = new ObjectMapper();
        // 指定要序列化的域
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson.setObjectMapper(objectMapper);
        // 值采用json序列化
        template.setValueSerializer(jackson);
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        // 设置hash key和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jackson);
        template.afterPropertiesSet();
        return template;
    }
}
RedisUtil.java
package com.example.util;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
@Component
public class RedisUtil {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    //===============缓存相关方法===============
    //指定缓存失效时间
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    //根据key获取过期时间,返回0代表为永久有效
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }
    //===============数据类型为String的相关方法===============
    //根据key值获取缓存值
    public Object stringGet(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }
    //根据key值存入数据类型为String的缓存值
    public boolean stringSet(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    //根据key值存入数据类型为String的缓存值并设置时间
    public boolean stringSetWithTime(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    //删除缓存
    public void stringDelete(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }
    //===============数据类型为Hash的相关方法===============
    //根据key和item获取缓存值
    public Object hashGet(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }
    //根据key和item存入数据类型为Hash的缓存值
    public boolean hashSet(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    //根据key和item存入数据类型为Hash的缓存值并设置时间
    public boolean hashSetWithTime(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    //删除缓存
    public void hashDelete(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }
    //===============数据类型为SET的相关方法===============
    //根据key值获取缓存值
    public Set<Object> setGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    //根据key值存入数据类型为SET的缓存值
    public long setSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    //根据key值存入数据类型为SET的缓存值并设置时间
    public long setSetWithTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    //删除缓存
    public long setDelete(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    //===============数据类型为LIST的相关方法===============
    //获取List缓存的内容,从start到end,若从0到-1代表所有值
    public List<Object> listGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    //根据key值存入数据类型为List的缓存值
    public boolean listSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    //根据key值存入数据类型为List的缓存值并设置时间
    public boolean listSetWithTime(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    //删除缓存
    public long listDelete(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}
启动项目后,浏览器输入 http://localhost:8080/redis/redisString ,(前台会报错,是因为这个请求只是触发后台的业务逻辑,没有前台页面展示)操作 String 类型的效果图如下所示;

启动项目后,浏览器输入  http://localhost:8080/redis/redisHash ,操作 Hash 类型的效果图如下所示;(注意一下,我之前代码写的是插入了四个值,只打印出来两个,是因为如果key值和item值一样,新来的值会覆盖原来的值,对比图和代码,你品,你细品。)

启动项目后,浏览器输入  http://localhost:8080/redis/redisSet ,操作 Set 类型的效果图如下所示;(Set是无序的)

启动项目后,浏览器输入  http://localhost:8080/redis/redisList ,操作 List 类型的效果图如下所示;

注:如果是根据本文系列文章来的,因为一开始就配置好了spring security,所以记得将该地址配给所登录的用户。或者开一个超级管理员账号,可以访问项目的任意目录,使用该管理员账号访问这些地址。
这是该学习系列的所有源码,如果有不明白的,想自己实操丰富其中内容的,可以下载到本地,
SpringBoot学习(七)—— springboot快速整合Redis的更多相关文章
- SpringBoot学习(七)-->SpringBoot在web开发中的配置
		
SpringBoot在web开发中的配置 Web开发的自动配置类:在Maven Dependencies-->spring-boot-1.5.2.RELEASE.jar-->org.spr ...
 - SpringBoot进阶教程(二十七)整合Redis之分布式锁
		
在之前的一篇文章(<Java分布式锁,搞懂分布式锁实现看这篇文章就对了>),已经介绍过几种java分布式锁,今天来个Redis分布式锁的demo.redis 现在已经成为系统缓存的必备组件 ...
 - springboot 学习之路 8 (整合websocket(1))
		
目录:[持续更新.....] spring 部分常用注解 spring boot 学习之路1(简单入门) spring boot 学习之路2(注解介绍) spring boot 学习之路3( 集成my ...
 - java框架之SpringBoot(11)-缓存抽象及整合Redis
		
Spring缓存抽象 介绍 Spring 从 3.1 版本开始定义了 org.springframework.cache.Cache 和 org.springframework.cache.Cache ...
 - SpringBoot第七篇:整合Mybatis-Plus
		
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/10881666.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言 一看这个名 ...
 - SpringBoot学习(四)-->SpringBoot快速入门,开山篇
		
Spring Boot简介 Spring Boot的目的在于创建和启动新的基于Spring框架的项目.Spring Boot会选择最适合的Spring子项目和第三方开源库进行整合.大部分Spring ...
 - SpringBoot进阶教程(三十)整合Redis之Sentinel哨兵模式
		
Redis-Sentinel是官方推荐的高可用解决方案,当redis在做master-slave的高可用方案时,假如master宕机了,redis本身(以及其很多客户端)都没有实现自动进行主备切换,而 ...
 - springboot 学习之路 20 (整合RabbitMQ)
		
整合RabbitMQ: 我的操作系统是window7 ,所以在整合ribbotMQ之前需要先安装rabbitMq服务:安装步骤请参考:window下安装RabbitMQ 这个详细介绍了安装步骤,请按 ...
 - springboot 学习之路 14(整合mongodb的Api操作)
		
springboot整合mongodb: mongodb的安装和权限配置 请点击连接参考 mongodb集成 : 第一步:引如pom文件 第二步:配置文件配置mongodb路径: 第三步:关于mon ...
 
随机推荐
- SpringBoot与MybatisPlus整合之活动记录(十五)
			
活动记录和正常的CRUD效果是一样的,此处只当一个拓展,了解即可 pom.xml <dependencies> <dependency> <groupId>org. ...
 - c#通过libreOffice实现 office文件转pdf文件
			
一.安装libreOffice 点击官网下载libreOffice 二.创建一个新的项目LibreOffice 创建一个新的项目,方便后面调用 添加下面代码 public class OfficeCo ...
 - Linux  wget 批量下载
			
需求:已知50个pdf的URL地址,需要批量下载,该怎么办呢? 方案一:使用wget自带的一个功能 -i 选项 从指定文件中读取下载地址,这样的好处是一直是这一个wget进程下载所有pdf,不会来回 ...
 - Web for pentester_writeup之Directory traversal篇
			
Web for pentester_writeup之Directory traversal篇 Directory traversal(目录遍历) 目录遍历漏洞,这部分有三个例子,直接查看源代码 Exa ...
 - hack the box -- sizzle  渗透过程总结,之前对涉及到域内证书啥的还不怎么了解
			
把之前的笔记搬运过来 --- 1 开了443,用smbclient建立空连接查看共享 smbclient -N -L \\\\1.1.1.1 Department Shares Operatio ...
 - 使用Typescript重构axios(三十)——添加axios.getUri方法
			
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
 - maven配置nexus私有仓库
			
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://mav ...
 - 前端Leader你应该知道的NPM包管理机制
			
npm install 命令 首先总结下npm 安装一个模块包的常用命令. /* 模块依赖会写入 dependencies 节点 */ npm install moduleName npm insta ...
 - requests模拟登陆的三种方式
			
###获取登录后的页面三种方式: 一.实例化seesion,使用seesion发送post请求,在使用他获取登陆后的页面 import requests session = requests.sess ...
 - python3.7.1安装Scrapy爬虫框架
			
python3.7.1安装Scrapy爬虫框架 环境:win7(64位), Python3.7.1(64位) 一.安装pyhthon 详见Python环境搭建:http://www.runoob.co ...