zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

SpringBoot 使用jedis整合redis实现缓存处理

RedisSpringBoot缓存 实现 处理 整合 Jedis 使用
2023-09-11 14:20:19 时间

SpringBoot 使用jedis整合redis实现缓存处理

一、前言

缓存即将常用的不会频繁变更的数据存入内存当中,从而减少数据库压力,提升访问速率。

使用redis作为缓存数据库

REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统是跨平台的非关系型数据库

redis基本结构:

  • String: 字符串
  • Hash: 散列
  • List: 列表
  • Set: 集合
  • Sorted Set: 有序集合

Redis 简介

Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。

Redis 与其他 key - value 缓存产品有以下三个特点

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储
  • Redis支持数据的备份,即master-slave模式的数据备份。

Redis 优势

  • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
  • 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

为什么使用redis做缓存?

使用redis作为缓存技术方案,主要是redis缓存技术的特点就在于高效,因为目前涉及的数据量逐渐增多,在对于数据的存储上面和sql以及服务器资源优化上面就来的特别的重要。而redis可以帮助解决由于数据库压力造成的延迟现象,针对于很少做改变的数据并且经常使用的数据,我们可以一致性加入内存。这样可以一方面减少数据库压力,一方面提高读写效率

二、环境配置

在服务器上安装redis服务,安装教程可参考 windows下安装redis详细教程

三、代码实现

1.新建Springboot项目,添加必要的依赖 pom.xml:

    <!-- web支持 -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	      <!-- redis -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-redis</artifactId>
		<!-- 默认指定了lettuce,我们需要排除 ,并且引入jedis的客户端-->
		<exclusions>
		  <exclusion>
			<groupId>io.lettuce</groupId>
			<artifactId>lettuce-core</artifactId>
		  </exclusion>
		</exclusions> 
	</dependency>
	<!-- jedis的客户端 -->
	<dependency>
		<groupId>redis.clients</groupId>
		<artifactId>jedis</artifactId>
	</dependency>
	<!-- lombok -->
	<dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

2. 在application.properties配置文件中添加 redis的相关配置

#Redis配置
spring.redis.host=127.0.0.1
##redis端口号
spring.redis.port=6379
##redis密码
spring.redis.redisPassword=
##redis连接超时时间(毫秒)
spring.redis.timeout=60000
##Redis默认情况下有16个分片,这里配置具体使用的分片,默认时0
spring.redis.database=0
##连接池最大连接数(使用负值表示没有限制)默认0
spring.redis.jedis.pool.max-active=1024
##连接池最大阻塞等待时间 (使用负值表示没有限制) 默认-1
spring.redis.jedis.pool.max-wait=60000
##连接池中的最大空闲连接 默认8
spring.redis.jedis.pool.max-idle=200
##连接池中的最小空闲连接 默认0
spring.redis.jedis.pool.min-idle=2
##连接耗时时是否阻塞
spring.redis.block-when-exhausted=true

3.SpringBoot 添加 自定义 redis 配置类

package com.example.redisdemo.config;

import com.example.redisdemo.utils.Tools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;


/**
 * 使用jedis整合redis
 *
 */
@Configuration
@PropertySource("classpath:application.properties")
public class RedisConfig {
	private static Logger logger = LoggerFactory.getLogger(RedisConfig.class);
	
	@Value("${spring.redis.host}")
	private String host;
	
	@Value("${spring.redis.port}")
	private int port;
	
	@Value("${spring.redis.redisPassword}")
	private String redisPassword;
	
	@Value("${spring.redis.timeout}")
	private int timeout;
	
	@Value("${spring.redis.database}")
	private String database;

	@Value("${spring.redis.jedis.pool.max-active}")
	private int maxActive;
	
	@Value("${spring.redis.jedis.pool.max-wait}")
	private long maxWait;
	
	@Value("${spring.redis.jedis.pool.max-idle}")
	private int maxIdle;
	
	@Value("${spring.redis.jedis.pool.min-idle}")
	private int minIdle;
	
	@Value("${spring.redis.block-when-exhausted}")
	private boolean blockWhenExhausted;
	
	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public String getRedisPassword() {
		return redisPassword;
	}

	public void setRedisPassword(String redisPassword) {
		this.redisPassword = redisPassword;
	}

	public int getTimeout() {
		return timeout;
	}

	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	@Bean
	public JedisPool redisPoolFactory() throws Exception{
		logger.info("JedisPool 注入成功!");
		logger.info("redis地址:"+host+":"+port);
		JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
		jedisPoolConfig.setMaxIdle(maxIdle);
		jedisPoolConfig.setMaxWaitMillis(maxWait);
		//连接耗尽时是否阻塞,false报异常,true阻塞直到超时,默认true
		jedisPoolConfig.setBlockWhenExhausted(blockWhenExhausted);
		//是否启用pool的jmx管理功能,默认true
		jedisPoolConfig.setJmxEnabled(true);
		
		JedisPool JedisPool;
		if(Tools.notEmpty(redisPassword)){
			JedisPool = new JedisPool(jedisPoolConfig,host, port, timeout,redisPassword);
		}else{
			JedisPool = new JedisPool(jedisPoolConfig,host, port, timeout);
		}
		logger.info("JedisPool:"+JedisPool);
		return JedisPool;
	}
}

4.创建redis工具类

package com.example.redisdemo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Map;


/**
 * redis工具类
 * @author Administrator
 *
 */
@Component
public class RedisUtil {
	
	@Autowired
	private  JedisPool jedisPool;
	
	//设置为0就是永不过期  单位秒
	private int expire = 60;
	/**
	 * 获取Jedis实例
	 * 
	 * @return
	 */
	public synchronized  Jedis getJedis() {
		try {
			if (jedisPool != null) {
				Jedis resource = jedisPool.getResource();
				resource.select(0); //设置为第二个库(db1) spring.redis.database
				return resource;
			} else {
				System.out.println("获取的Redis链接为null");
				return null;
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("获取Redis链接出错:" + e.getMessage());
			return null;
		}
	}

	/**
	 * get value from redis
	 * 
	 * @param key
	 * @return
	 */
	public byte[] get(byte[] key) {
		Jedis jedis = getJedis();
		byte[] value = null;
		try {
			value = jedis.get(key);
		} finally {
			jedis.close();
		}
		return value;
	}

	/**
	 * get value from redis
	 * 
	 * @param key
	 * @return
	 */
	public String get(String key) {
		Jedis jedis = getJedis();
		String value = null;
		try {
			value = jedis.get(key);
		} finally {
			jedis.close();
		}
		return value;
	}

	/**
	 * set
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	public void set(byte[] key, byte[] value) {
		Jedis jedis = getJedis();
		try {
			jedis.set(key, value);
			if (expire != 0) {
				jedis.expire(key, expire);
			}
		} finally {
			jedis.close();
		}
	}

	/**
	 * set
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	public void set(String key, String value) {
		Jedis jedis = getJedis();
		try {
			jedis.set(key, value);
			if (expire != 0) {
				jedis.expire(key, expire);
			}
		} finally {
			jedis.close();
		}
	}

	/**
	 * set
	 * 
	 * @param key
	 * @param value
	 * @param expire
	 * @return
	 */
	public void set(byte[] key, byte[] value, int expire) {
		Jedis jedis = getJedis();
		try {
			jedis.set(key, value);
			if (expire != 0) {
				jedis.expire(key, expire);
			}
		} finally {
			jedis.close();
		}
	}

	/**
	 * 添加key=String,value=HashMap<String,String>类型的数据 hmset
	 * 
	 * @param key
	 * @param inMap
	 * @param expire
	 *            生命周期 单位秒
	 */
	public void hmset(String key, Map<String, String> inMap, int expire) {
		Jedis jedis = getJedis();
		try {
			jedis.hmset(key, inMap);
			if (expire != 0) {
				jedis.expire(key, expire);
			}
		} finally {
			jedis.close();
		}
	}

	/**
	 * 获取value类型为HashMap<String,String>类型的数据
	 * 
	 * @param key
	 * @return
	 */
	public Map<String, String> hgetAll(String key) {
		Jedis jedis = getJedis();
		Map<String, String> value = null;
		try {
			value = jedis.hgetAll(key);
		} finally {
			jedis.close();
		}
		return value;
	}

	/**
	 * del
	 * 
	 * @param key
	 */
	public void del(byte[] key) {
		Jedis jedis = getJedis();
		try {
			jedis.del(key);
		} finally {
			jedis.close();
		}
	}

	/**
	 * del
	 * 
	 * @param key
	 */
	public void del(String key) {
		Jedis jedis = getJedis();
		try {
			jedis.del(key);
		} finally {
			jedis.close();
		}
	}

	/**
	 * 判断指定键是否存在
	 * 
	 * @param key
	 * @return
	 */
	public boolean exists(String key) {
		Jedis jedis = getJedis();
		boolean flag = jedis.exists(key);
		jedis.close();
		return flag;
	}

	/**
	 * 获取key对应的值剩余存活时间
	 * 
	 * @param key
	 * @return 正数:剩余的时间(秒) 负数:已过期
	 */
	public Long ttlKey(String key) {
		Jedis jedis = getJedis();
		try {
			return jedis.ttl(key);
		} catch (Exception e) {
			System.out.println(" -- Redis 获取key对应的值剩余存活时间出错,出错原因:" + e);
			e.printStackTrace();
			return 0L;
		} finally {
			jedis.close();
		}
	}

	/**
	 * 获取key对应的值剩余存活时间
	 * 
	 * @param key
	 * @return 正数:剩余的时间(秒) 负数:已过期
	 */
	public Long ttlKey(byte[] key) {
		Jedis jedis = getJedis();
		try {
			return jedis.ttl(key);
		} catch (Exception e) {
			System.out.println(" -- Redis 获取key对应的值剩余存活时间出错,出错原因:" + e);
			e.printStackTrace();
			return 0L;
		} finally {
			jedis.close();
		}
	}

	/**
	 * 存储对象
	 * 
	 * @param key
	 * @param obj
	 * @param expire
	 */
	public void setObject(String key, Object obj, int expire) {
		Jedis jedis = getJedis();
		byte[] data = ObjTOSerialize(obj);
		jedis.set(key.getBytes(), data);
		if (expire != 0) {
			jedis.expire(key, expire);
		}
		jedis.close();
	}

	/**
	 * 获取对象
	 * 
	 * @param key
	 * @return
	 */
	public Object getObject(String key) {
		Jedis jedis = getJedis();
		byte[] data = jedis.get(key.getBytes());
		Object obj = null;
		if (data != null) {
			obj = unSerialize(data);
		}
		jedis.close();
		return obj;
	}

	/**
	 * 
	 * 序列化一个对象
	 * 
	 * @param obj
	 * @return
	 */
	public byte[] ObjTOSerialize(Object obj) {
		ObjectOutputStream oos = null;
		ByteArrayOutputStream byteOut = null;
		try {
			byteOut = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(byteOut);
			oos.writeObject(obj);
			byte[] bytes = byteOut.toByteArray();
			return bytes;
		} catch (Exception e) {
			System.out.println("-- Redis序列化对象出错:" + e);
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 反序列化一个对象
	 * 
	 * @param bytes
	 * @return
	 */
	public Object unSerialize(byte[] bytes) {
		ByteArrayInputStream in = null;
		try {
			in = new ByteArrayInputStream(bytes);
			ObjectInputStream objIn = new ObjectInputStream(in);
			return objIn.readObject();
		} catch (Exception e) {
			System.out.println("-- Redis反序列化对象出错:" + e);
			e.printStackTrace();
		}
		return null;
	}
	
}

5.User 实体类

package com.example.redisdemo.entity;

import lombok.Data;

import java.io.Serializable;

/**
 * 用户表
 * @author qzz
 */
@Data
public class User implements Serializable {

    /**
     * 序列化
     */
    private static final long serialVersionUID = -4938532764925446470L;

    private Integer user_id;

    private String openid;

    private String user_name;

    private String user_phone;
}

6.redis使用实例(以存取为例):

在需要redis存取的类中,注入RedisUtil ,然后使用 redisUtil 对象调用 存取 方法。

package com.example.redisdemo.controller;

import com.example.redisdemo.config.RedisUtil;
import com.example.redisdemo.entity.User;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * @author qzz
 */
@RestController
@RequestMapping("/user")
public class UserController {

    /**
     * 初始3rd_session有效期 单位s  有效期为一天
     */
    private static final int  expire = 60*60*24;

    /**
     * 注入 RedisUtil
     */
    @Autowired
    private RedisUtil redisUtil;

    /**
     * 获取用户策略:先从缓存中获取用户,没有则取数据表中的数据,再将数据写入缓存
     * @param userId
     * @return
     */
    @GetMapping("/getData")
    public Map<String, String> getUserInfoById(String userId){

        String userKey = "user_"+userId;

        //从redis存储中取所需数据
        Map<String, String> redisDataMap = redisUtil.hgetAll(userKey);
        if(redisDataMap==null || redisDataMap.size()==0){
            System.out.println("缓存不存在");
            //缓存不存在

            //模拟从数据库中获取用户信息
            User userInfo = new User();
            userInfo.setUser_id(1);
            userInfo.setUser_name("张三");
            userInfo.setUser_phone("15720821396");


            //把用户信息存入redis中
            redisDataMap.put("user_id",String.valueOf(userInfo.getUser_id()));
            redisDataMap.put("user_name",String.valueOf(userInfo.getUser_name()));
            redisDataMap.put("user_phone",String.valueOf(userInfo.getUser_phone()));
            //插入缓存
            redisUtil.hmset(userKey, redisDataMap,expire);
        }else{
            System.out.println("缓存存在,用户信息:"+redisDataMap.toString());
        }
        return redisDataMap;
    }
}

7.启动项目,进行测试

在这里插入图片描述
在浏览器中输入http://localhost:8080/user/getData?userId=1第一次访问:
在这里插入图片描述
再次访问:
在这里插入图片描述

8.示例代码

点击此处可下载