spring boot使用Jedis整合Redis



Spring Boot整合Redis有两种方式,分别是Jedis和RedisTemplate,那么它们二者有什么区别呢?

1、Jedis是Redis官方推荐的面向Java操作Redis的客户端,可以通过JedisPool来获取Jedis连接进行set、get、del等操作,相对简单。RedisTemplate是SpringDataRedis中对JedisAPI的高度封装。

2、RedisTemplate相对于Jedis来说更方便更换Redis客户端,比Jedis多了自动管理连接池的特性。


spring boot使用jedis整合redis


1、添加依赖

<!--Redis客户端: jedis-->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.3</version>
</dependency>

2、application.yml配置Redis配置属性

#Redis配置属性
redis:
  #主机IP
  host: 136.50.201.130
  #Redis默认端口号
  port: 6379
  #Redis服务器连接密码(默认为空)
  password:
  #Redis数据库索引(默认为0),redis默认提供16个数据库(0-15)
  database: 0
  #jedis连接池
  pool:
    #连接池中允许的最大连接数(默认值为8):即能同时建立的‘最大连接个数’,连接全部用完,则需进行等待(使用负值表示没有限制)
    max-active: 1024
    #允许池中空闲的最小连接数:低于minIdle时,将创建新的连接
    min-idle: 0
    #连接池中最多可空闲maxIdle个连接(默认值为8) ,这里取值为100,表示即使没有数据库连接时依然可以保持100空闲的连接,而不被清除,随时处于待命状态
    max-idle: 100
    #等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
    max-wait: 15000
    #连接超时时间(毫秒)
    timeout: 5000

3、读取yml文件中redis的配置属性,注入JedisPoolConfig对象,然后根据JedisPoolConfig和redis相关配置属性创建JedisPool连接池,再通过getResource()从JedisPool连接池获取jedis连接对象。

package com.cd.o2o.cache;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@Configuration //标注@Configuration的类,相当于一个xml配置文件
public class JedisPoolUtil {

    //redis配置属性读取
    @Value("${redis.host}")
    private String host;
    @Value("${redis.port}")
    private int port;
    @Value("${redis.database}")
    private int database;

    @Value("${redis.pool.max-active}")
    private int maxActive;
    @Value("${redis.pool.max-idle}")
    private int maxIdle;
    @Value("${redis.pool.min-idle}")
    private int minIdle;
    @Value("${redis.pool.max-wait}")
    private long maxWaitMillis;

    @Autowired
    private JedisPoolConfig jedisPoolConfig;
    @Autowired
    private JedisPool jedisPool;

    @Bean //标注@Bean后表明返回对象会被当做一个Bean注册到Spring IoC容器
    public JedisPoolConfig createJedisPoolConfig(){
        JedisPoolConfig jedisPoolConfig = null;
        try{
            //创建连接池配置类
            jedisPoolConfig = new JedisPoolConfig();
            //控制连接池最多可以分配多少个jedis实例
            jedisPoolConfig.setMaxTotal(maxActive);
            //连接池最大空闲连接数
            jedisPoolConfig.setMaxIdle(maxIdle);
            //连接池最小空闲连接数,小于这个数会自动创建连接
            jedisPoolConfig.setMinIdle(minIdle);
            //连接池最大阻塞时间
            jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        }catch (Exception e){
            e.printStackTrace();
        }
        return jedisPoolConfig;
    }

    @Bean
    public JedisPool createJedisPool(){
        JedisPool jedisPool = null;
        try{
            //创建jedisPool连接池
            jedisPool = new JedisPool(jedisPoolConfig,host,port,database);
        }catch (Exception e){
            e.printStackTrace();
        }
        return jedisPool;
    }

    @Bean
    public Jedis getJedis(){
        //获取jedis连接对象
        return jedisPool.getResource();
    }
}

4、编写redis工具类,通过jedis连接对象获取对key进行操作,这里我仅提供string存储结构的操作方法。(调用jedis连接对象后,记得释放连接)

package com.cd.o2o.cache;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.util.SafeEncoder;

import java.util.Set;

@Component  //标注@Component,表示将该类注册到Spring IoC容器
public class JedisUtil {

    @Autowired
    private Jedis jedis;

    //操作key的方法 (用于判断某个key是否存在,需不需要清空key里的数据),这是对key的操作

    /**
     * 判断某个Key是否存在
     *
     * @param key
     * @return boolean
     */
    public boolean exists(String key){
        boolean exists = false;
        try{
            //调用jedis的exists()方法,判断某个Key是否存在于Redis服务器中
            exists = jedis.exists(key);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭jedis连接,避免资源占用
            jedis.close();
        }
        return exists;
    }


    /**
     * 查找所有给定模式的key
     *
     * @param pattern  key表达式:*表示多个 ?表示一个 (粒如:shop*表示所有以shop开头的key)
     * @return
     */
    public Set<String> keys(String pattern){
        Set<String> set = null;
        try{
            //调用jedis的keys()方法,获取匹配的key,并保存到Set集合中
            set = jedis.keys(pattern);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭jedis连接,避免资源占用
            jedis.close();
        }
        return set;
    }

    /**
     * 删除key对应的记录,可以是多个记录
     *
     * @param keys
     * @return 删除的记录数
     */
    public long del(String... keys){
        long count = 0;
        try{
            //调用jedis的del()方法将相关的Keys删除,并返回删除的记录数
            count = jedis.del(keys);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭jedis连接,避免资源占用
            jedis.close();
        }
        return count;
    }

    /**
     * 清除所有的key
     * @return 状态码
     */
    public String flushAll(){
        String state = null;
        try{
            //调用jedis的flushAll()方法,清空所有的key
            state = jedis.flushAll();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭jedis连接,避免资源占用
            jedis.close();
        }
        return state;
    }

    /**
     * 修改key名,如果新key已存在,则旧key的值会覆盖新key的值
     *
     * @param oldKey
     * @param newKey
     * @return 状态码
     */
    public String rename(String oldKey,String newKey){
        String state = null;
        try{
            state = jedis.rename(SafeEncoder.encode(oldKey),SafeEncoder.encode(newKey));
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭jedis连接,避免资源占用
            jedis.close();
        }
        return state;
    }


    /**
     * 在新key不存在时,将旧key修改成该新key的名称
     *
     * @param oldKey
     * @param newKey
     * @return 状态码
     */
    public Long renamenx(String oldKey,String newKey){
        long status = 0;
        try{
            //重命名key
            status = jedis.renamenx(oldKey,newKey);
        }catch (Exception e){
            //关闭jedis连接,避免资源占用
            jedis.close();
        }
        return status;
    }


    //对存储结构为String的操作(Redis中,字符串类型的value最大可容纳的数据为512M),这是对value的操作

    /**
     * 根据key名,获取其存储数据
     * @param key
     * @return
     */
    public String get(String key){
        String value = null;
        try{
            //获取指定key的存储数据
            value = jedis.get(key);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭jedis连接,避免资源占用
            jedis.close();
        }
        return value;
    }

    /**
     * 添加记录,如果记录已存在则覆盖原有的value
     * @param key
     * @param value
     * @return
     */
    public String set(String key,String value){
        String state = null;
        try{
            //设置指定key的存储数据
            state = jedis.set(key,value);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭jedis连接,避免资源占用
            jedis.close();
        }
        return state;
    }
}

ok,相关操作已完成


  实际项目开发中,我们会先从redis中获取指定数据,如果redis中没有该数据,那么我们再从mysql数据库中取出该数据。并且为了下次能直接从redis中取出该数据,需要将从mysql中取出的数据添加到redis中。由于前面我指定了string作为redis的存储结构,所以需要将从mysql中取出的数据通过json解析工具解析成string,然后再添加进redis中。

cd4356

package com.cd.o2o.service.impl;

import com.cd.o2o.cache.JedisUtil;
import com.cd.o2o.dao.AreaDao;
import com.cd.o2o.entity.Area;
import com.cd.o2o.service.AreaService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.List;

@Service("areaService")
public class AreaServiceImpl implements AreaService {

    @Autowired
    private AreaDao areaDao;
    @Autowired
    private JedisUtil jedisUtil;
    //指定key前缀
    private static final String AREALIST = "arealist";

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public List<Area> getAreaList() {
        //定义Redis的key名
        String key = AREALIST;
        //定义接收对象
        List<Area> areaList = null;
        //定义Jackson数据转换操作类
        ObjectMapper objectMapper = new ObjectMapper();

        //判断key是否存在
        if(!jedisUtil.exists(key)){
            //若key不存在,则从数据库中取出相应数据,并添加进redis里
            areaList = areaDao.queryArea();
            String jsonString = null;
            try {
                //将从数据库中取出的实体类集合类型数据转化成String类型数据
                jsonString = objectMapper.writeValueAsString(areaList);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
                //抛出RuntimeException才能回滚事务
                throw new RuntimeException(e.getMessage());
            }
            //将转化后的区域信息设置进指定的key中
            jedisUtil.set(key,jsonString);
        }else {
            //若key存在,则从redis中取出该key对应的数据
            String jsonString = jedisUtil.get(key);
            //指定要将string转化成的复杂集合类型  List<Area>
            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class,Area.class);
            try {
                //将json字符串转化成List<Area>对象
                areaList = objectMapper.readValue(jsonString,javaType);
            } catch (IOException e) {
                e.printStackTrace();
                //抛出RuntimeException才能回滚事务
                throw new RuntimeException(e.getMessage());
            }
        }
        return areaList;
    }
}



总结
  1. 添加jedis依赖
  2. 在yml文件中配置redis的相关配置属性
  3. 读取yml中redis的配置属性,注入JedisPoolConfig对象,然后根据JedisPoolConfig及相关属性配置JedisPool连接池,再通过getResource()方法从JedisPool连接池中获取jedis连接对象
  4. 调用Jedis连接对象进行set、get、del等操作
  5. 如果redis缓存中有指定数据,则从缓存中获取,否则从mysql数据库中获取,再添加进redis缓存中

redis使用中经常出现 Could not get a resource from the pool 异常,解决办法总结

spring boot基本操作

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章