发表于: 2020-08-21 23:23:25

2 1252


今天完成的事:

spring和redis的整合,并在项目中使用。

首先要引入依赖包(一定要注意版本问题),下面是根据网上了解的两个能匹配的版本。

<dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-pool2</artifactId>
 <version>2.4.2</version>
</dependency>
<dependency>
 <groupId>redis.clients</groupId>
 <artifactId>jedis</artifactId>
 <version>2.4.2</version>
</dependency>
<dependency>
 <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-redis</artifactId>
 <version>1.7.2.RELEASE</version>

然后是redis的配置文件

redis.host=127.0.0.1
redis.port=6600
#最大连接数。
redis.maxTotal=600
#最大空闲连接数
redis.maxIdle=300
#当连接池资源耗尽时,调用者最大阻塞时间,超时将抛出异常
redis.maxWaitMillis=1000
#指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个(默认false)
redis.testOnBorrow=true

spring-redis.xml 

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
      xsi:schemaLocation="
                    http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                    http://www.springframework.org/schema/context
                    http://www.springframework.org/schema/context/spring-context-4.0.xsd ">
   <context:property-placeholder ignore-unresolvable="true" location="classpath:redis.properties"/>
   <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
       <property name="maxTotal" value="${redis.maxTotal}"/>
       <property name="maxIdle" value="${redis.maxIdle}"/>
       <property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
       <property name="testOnBorrow" value="${redis.testOnBorrow}"/>

   </bean>
   <!--spring-redis连接池管理工厂-->
   <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
       <property name="hostName" value="${redis.host}"/>
       <property name="port" value="${redis.port}"/>
       <property name="timeout" value="${redis.timeout}"/>
       <property name="poolConfig" ref="poolConfig"/>
       <property name="usePool" value="true"/>
   </bean>
   <!-- 定义模板 -->
   <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
       <property name="connectionFactory" ref="jedisConnectionFactory" />
       <property name="keySerializer">
           <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
       </property>
       <property name="valueSerializer">
           <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
       </property>
       <property name="hashKeySerializer">
           <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
       </property>
       <property name="hashValueSerializer">
           <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
       </property>
       <!--开启事务  -->
       <property name="enableTransactionSupport" value="true"></property>

   </bean>

   <bean id="redisService" class="com.jnshu.Util.RedisService">
       <constructor-arg ref="redisTemplate"/>
   </bean>
</beans>

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

所以根据网上教程把redis常用的方法提取出来封装到RedisService中

package com.jnshu.Util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
* @ClassName RedisService
* @Description
* @Author 韦延伦
* @Date 2020/8/21 15:09
* @Version 1.0
*/
public class RedisService {
private Logger log = LoggerFactory.getLogger(this.getClass());
   private final RedisTemplate<String, Object> redisTemplate;

   public RedisService(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
   }
/**
    * 指定缓存失效时间
    *
    * @param key  
    * @param time 时间(秒)
    * @return
    */
   public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
           }
return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 根据key 获取过期时间
    *
    * @param key 键 不能为null
    * @return 时间(秒) 返回0代表为永久有效
    */
   public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
   }

/**
    * 判断key是否存在
    *
    * @param key
    * @return true 存在 false不存在
    */
   public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 删除缓存
    *
    * @param key 可以传一个值 或多个
    */
   @SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
           } else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
           }
}
}

// ============================String=============================

   /**
    * 普通缓存获取
    *
    * @param key
    * @return
    */
   public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
   }

/**
    * 普通缓存放入
    *
    * @param key  
    * @param value
    * @return true成功 false失败
    */
   public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
           return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }

}

/**
    * 普通缓存放入并设置时间
    *
    * @param key  
    * @param value
    * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
    * @return true成功 false 失败
    */
   public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
           } else {
set(key, value);
           }
return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 递增
    *
    * @param key
    * @return
    */
   public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
       }
return redisTemplate.opsForValue().increment(key, delta);
   }

/**
    * 递减
    *
    * @param key
    * @return
    */
   public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
       }
return redisTemplate.opsForValue().increment(key, -delta);
   }

// ================================Map=================================

   /**
    * HashGet
    *
    * @param key  键 不能为null
    * @param item 项 不能为null
    * @return
    */
   public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
   }

/**
    * 获取hashKey对应的所有键值
    *
    * @param key
    * @return 对应的多个键值
    */
   public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
   }

/**
    * HashSet
    *
    * @param key
    * @param map 对应多个键值
    * @return true 成功 false 失败
    */
   public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
           return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * HashSet 并设置时间
    *
    * @param key  
    * @param map  对应多个键值
    * @param time 时间(秒)
    * @return true成功 false失败
    */
   public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
           if (time > 0) {
expire(key, time);
           }
return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 向一张hash表中放入数据,如果不存在将创建
    *
    * @param key  
    * @param item  
    * @param value
    * @return true 成功 false失败
    */
   public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
           return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 向一张hash表中放入数据,如果不存在将创建
    *
    * @param key  
    * @param item  
    * @param value
    * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
    * @return true 成功 false失败
    */
   public boolean hset(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) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 删除hash表中的值
    *
    * @param key  键 不能为null
    * @param item 项 可以使多个 不能为null
    */
   public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
   }

/**
    * 判断hash表中是否有该项的值
    *
    * @param key  键 不能为null
    * @param item 项 不能为null
    * @return true 存在 false不存在
    */
   public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
   }

/**
    * hash递增 如果不存在,就会创建一个 并把新增后的值返回
    *
    * @param key  
    * @param item
    * @param by   要增加几(大于0)
    * @return
    */
   public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
   }

/**
    * hash递减
    *
    * @param key  
    * @param item
    * @param by   要减少记(小于0)
    * @return
    */
   public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
   }

// ============================set=============================

   /**
    * 根据key获取Set中的所有值
    *
    * @param key
    * @return
    */
   public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
       } catch (Exception e) {
log.error("redis error: ", e);
           return null;
       }
}

/**
    * 根据value从一个set中查询,是否存在
    *
    * @param key  
    * @param value
    * @return true 存在 false不存在
    */
   public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 将数据放入set缓存
    *
    * @param key    
    * @param values 值 可以是多个
    * @return 成功个数
    */
   public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
       } catch (Exception e) {
log.error("redis error: ", e);
           return 0;
       }
}

/**
    * 将set数据放入缓存
    *
    * @param key    
    * @param time   时间(秒)
    * @param values 值 可以是多个
    * @return 成功个数
    */
   public long sSetAndTime(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) {
log.error("redis error: ", e);
           return 0;
       }
}

/**
    * 获取set缓存的长度
    *
    * @param key
    * @return
    */
   public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
       } catch (Exception e) {
log.error("redis error: ", e);
           return 0;
       }
}

/**
    * 移除值为value的
    *
    * @param key    
    * @param values 值 可以是多个
    * @return 移除的个数
    */
   public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
           return count;
       } catch (Exception e) {
log.error("redis error: ", e);
           return 0;
       }
}
// ===============================list=================================

   /**
    * 获取list缓存的内容
    *
    * @param key  
    * @param start 开始
    * @param end   结束 0 到 -1代表所有值
    * @return
    */
   public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
       } catch (Exception e) {
log.error("redis error: ", e);
           return null;
       }
}

/**
    * 获取list缓存的长度
    *
    * @param key
    * @return
    */
   public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
       } catch (Exception e) {
log.error("redis error: ", e);
           return 0;
       }
}

/**
    * 通过索引 获取list中的值
    *
    * @param key  
    * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
    * @return
    */
   public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
       } catch (Exception e) {
log.error("redis error: ", e);
           return null;
       }
}

/**
    * 将list放入缓存
    *
    * @param key  
    * @param value
    * @return
    */
   public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
           return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 将list放入缓存
    *
    * @param key  
    * @param value
    * @param time  时间(秒)
    * @return
    */
   public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
           if (time > 0) {
expire(key, time);
           }
return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 将list放入缓存
    *
    * @param key  
    * @param value
    * @return
    */
   public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
           return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 将list放入缓存
    *
    * @param key  
    * @param value
    * @param time  时间(秒)
    * @return
    */
   public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
           if (time > 0) {
expire(key, time);
           }
return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 根据索引修改list中的某条数据
    *
    * @param key  
    * @param index 索引
    * @param value
    * @return
    */
   public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
           return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    * 移除N个值为value
    *
    * @param key  
    * @param count 移除多少个
    * @param value
    * @return 移除的个数
    */
   public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
           return remove;
       } catch (Exception e) {
log.error("redis error: ", e);
           return 0;
       }
}

// ===============================sorted set=================================

   /**
    * 向有序集合添加一个成员的
    *
    * ZADD key score1 member1 [score2 member2]
    *
    */
   public boolean zadd(String key, Object member, double score, long time) {
try {
redisTemplate.opsForZSet().add(key, member, score);
           if (time > 0) {
expire(key, time);
           }
return true;
       } catch (Exception e) {
log.error("redis error: ", e);
           return false;
       }
}

/**
    *     ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT]
    通过分数返回有序集合指定区间内的成员
    *
    */
   public Set<Object> zRangeByScore(String key, double minScore, double maxScore) {
try {
return redisTemplate.opsForZSet().rangeByScore(key, minScore, maxScore);
       } catch (Exception e) {
log.error("redis error: ", e);
           return null;
       }
}

/**
    *     ZSCORE key member
    返回有序集中,成员的分数值
    *
    */
   public Double zscore(String key, Object member) {
try {
return redisTemplate.opsForZSet().score(key, member);
       } catch (Exception e) {
log.error("redis error: ", e);
           return null;
       }
}

/**
    *     ZRANK key member 返回有序集合中指定成员的索引
    *
    */
   public Long zrank(String key, Object member) {
try {
return redisTemplate.opsForZSet().rank(key, member);
       } catch (Exception e) {
log.error("redis error: ", e);
           return null;
       }
}

/**
    * Zscan 迭代有序集合中的元素(包括元素成员和元素分值)
    *
    */
   public Cursor<ZSetOperations.TypedTuple<Object>> zscan(String key) {
try {
Cursor<ZSetOperations.TypedTuple<Object>> cursor = redisTemplate.opsForZSet().scan(key, ScanOptions.NONE);
           return cursor;
       } catch (Exception e) {
log.error("redis error: ", e);
           return null;
       }
}
}

在项目中使用

RedisService redisService= CacheUtil.getRedis();
   private static final String KEY="studentList";

   @Override
   @SuppressWarnings("unchecked")
//    @CacheResult(key = "studentKey",expireSecond = 180)
   public List<Student> selectAll() {
System.out.println("实际方法开始");
       List<Student> studentList=null;
       if(!redisService.hasKey(KEY)){
studentList=studentMapper.selectAll();
           redisService.lSet(KEY,studentList);
       }else {
studentList=(List<Student>)(List)redisService.lGet(KEY,0,-1);
       }
System.out.println("实际方法结束");
       return studentList;
   }

测试效果:

第一次执行:

第二次执行

成功从redis中拿到学生数据


明天的计划:

继续压测。

遇到的问题:

Caused by: java.io.InvalidClassException: com.jnshu.pojo.Student; local class incompatible: stream classdesc serialVersionUID = 467859405852801897,

 local class serialVersionUID = 4329755407163153857

因为 Java 的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM 会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。

解决这个异常的方法其实也简单,就是定义serialVersionUID,定义的方式有两种,分别为:

a.采用默认的1L,具体为private static final long serialVersionUID = 1L;

b.根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,例如 private static final long serialVersionUID = XXXL;

收获:

redis在项目中的简单使用。


返回列表 返回列表
评论

    分享到