记自己在spring中使用redis遇到的两个坑
本人在spring中使用redis作为缓存时,遇到两个坑,现在记录如下,算是作为自己的备忘吧,文笔不好,望大家见谅;
一、配置文件
<!-- 加载Properties文件 -->
<bean id="configurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:config.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean> <!-- 配置JedisPoolConfig实例 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!--最大空闲数,数据库连接的最大空闲时间。超过空闲时间,数据库连接将被标记为不可用,然后被释放。设为0表示无限制-->
<property name="maxIdle" value="300" />
<!--连接池的最大数据库连接数。设为0表示无限制-->
<property name="maxTotal" value="600" />
<!--最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制-->
<property name="maxWaitMillis" value="1000" />
<!--在borrow一个jedis实例时,是否提前进行alidate操作;如果为true,则得到的jedis实例均是可用的-->
<property name="testOnBorrow" value="true" />
<!--每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3-->
<property name="numTestsPerEvictionRun" value="3"/>
<!--逐出连接的最小空闲时间 默认1800000毫秒(30分钟)-->
<property name="minEvictableIdleTimeMillis" value="300000"/>
<!--逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1-->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!--在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="true" />
</bean> <!-- 配置JedisConnectionFactory,类似于数据库的连接池 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}"></property>
<property name="port" value="${redis.port}"></property>
<property name="password" value="${redis.password}"></property>
<property name="database" value="${redis.dbIndex}"></property>
<property name="poolConfig" ref="jedisPoolConfig"></property>
<property name="timeout" value="100000"></property>
</bean> <!-- 配置RedisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
<!--如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!! -->
<property name="keySerializer" >
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer" >
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
</property>
<!--开启事务 -->
<property name="enableTransactionSupport" value="true"></property>
</bean>
注:可以看到我redis的配置中,对于hash的key使用的是StringRedisSerializer序列化,而对于value使用的是GenericJackson2JsonRedisSerializer序列化。
二、坑一
// 源代码
HashOperations ho = redisTemplate.opsForHash();
Boolean flag = ho.hasKey(“key”, "key1");
if (flag) {
// 处理逻辑
}
上面这段代码,当redis中值不存在时,按照官方的说明文档,应该返回false。但是我使用的时候,hasKey方法时而返回的是null,时而返回的false,导致空指针异常。搞了半天我也没搞明白为啥返回false,最后没办法我妥协了(大神如果知道可以回复我)。
// 妥协后代码
HashOperations ho = redisTemplate.opsForHash();
Boolean flag = ho.hasKey(“key”, "key1");
if (flag != null && flag) {
// 处理逻辑
}
三、坑二
// 将Map放到redis的hash中
public void putRedisHash1(){
HashOperations ho = redisTemplate.opsForHash();
Map<String, Boolean> tempMap = new HashMap<String, Boolean>(3){{
put("isRegistered",false);
put("isWeChat",false);
put("isAliPay",false);
}};
ho.put("key", "key1", tempMap);
} // 将Map放到redis的hash中
public void putRedisHash2(){
HashOperations ho = redisTemplate.opsForHash();
Map<String, Boolean> tempMap = new HashMap<String, Boolean>(3);
tempMap.put("isRegistered",false);
tempMap.put("isWeChat",false);
tempMap.put("isAliPay",false);
ho.put("key", "key1", tempMap);
}
这两个方法的功能是一样的,但是第一个方法是在Map初始化同时将值放入其中,第二个方法是Map初始化以后将值放入其中,执行结果是一样,但是在redis中的存储形式完全不同。由于Hash的value使用的是GenericJackson2JsonRedisSerializer序列化,所以为了反序列化方便,它会存储
@class“”这个字段,由于Map初始化时机不同,导致相同内容在redis中@class内容不一致,为了使用方便,推荐第二种,即在Map初始化以后将值放入其中。

记自己在spring中使用redis遇到的两个坑的更多相关文章
- spring中订阅redis键值过期消息通知
1.首先启用redis通知功能(ubuntu下操作):编辑/etc/redis/redis.conf文件,添加或启用以下内容(过期通知): notify-keyspace-events Ex 或者登陆 ...
- 在Spring中使用Redis Lua脚本批量删除缓存
背景 之前分享了一篇利用lua脚本批量删除redis的key的文章.现在项目中我打算使用spring的缓存,而Spring缓存以前我是用ehcache来做实现的.没发现什么问题..这次我换成redis ...
- Spring中使用Redis
普通使用Redis的方法很简单,前面的文章也有讲解,这篇文章主要就是讲解通过注解的方式实现Spring和Redis的整合.这里我们创建了3个类:1.Config 全局配置类,相当于xml配置文件2.R ...
- spring中添加redis缓存
1.单机版的添加 spring里面配置 <bean id="redisClient" class="redis.clients.jedis.JedisPool&qu ...
- Spring下使用Redis
在Spring中使用Redis使用使用两个依赖包jedis.jar.spring-data-redis.jar 一下是Maven项目pom.xml添加依赖 <!--jedis.jar --> ...
- 在SpringBoot中引入Redis
前言 之前我们只是在Spring中加入Redis用于session的存放,并没有对redis进行主动的存放,这次我们需要加入redis工具类来方便我们在实际使用过程中操作redis 已经加入我的git ...
- Spring+Dubbo集成Redis的两种解决方案
当下我们的系统数据库压力都非常大,解决数据库的瓶颈问题势在必行,为了解决数据库的压力等需求,我们常用的是各种缓存,比如redis,本文就来简单讲解一下如何集成redis缓存存储,附github源码. ...
- Spring中的FactoryBean
从SessionFactory说起: 在使用SSH集成开发的时候,我们有时候会在applicationContext.xml中配置Hibernate的信息,以下是配置SessionFactory的一段 ...
- (转)spring中的拦截器(HandlerInterceptor+MethodInterceptor)
1. 过滤器跟拦截器的区别 在说拦截器之前,不得不说一下过滤器,有时候往往被这两个词搞的头大. 其实我们最先接触的就是过滤器,还记得web.xml中配置的<filter>吗~ 你应该知道 ...
随机推荐
- Android开发——Notification通知的各种Style详解
本来是想与之前讲解使用Notification通知使用一起写的,查看了资料,觉得有必要将这Style部分单独拿出来讲解 前篇:Android开发——Notification通知的使用及Notifica ...
- 【开源】SpringBootNetty聊天室V1.2.0升级版本介绍
前言 SpringBoot!微服务微架构的基础,Netty通信框架的元老级别框架,即之前的SpringBoot与Netty的实现聊天室的功能后已经过了不到一周的时间啦,今天我们更新了项目版本从V1.0 ...
- Dubbo+ZK与Eureka注册中心比较
Eureka可以很好的应对网络故障导致部分节点失去联系的情况,而不会像zk那样因为选举导致整个集群不可用 dubbo + zk 当向注册中心查询服务注册列表时,可以容忍注册中心返回的是几分钟以前的注册 ...
- JavaScript的工作原理:解析、抽象语法树(AST)+ 提升编译速度5个技巧
这是专门探索 JavaScript 及其所构建的组件的系列文章的第 14 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...
- 解决Windows下栈内存过小的问题
本地是windows环境 这个需要对你的IDE进行更改 拿Dev-C++来说 加入一条编译命令就好 -Wl,--stack= 评测机是Windows环境 很简单 在你的代码前面加一行 #pragma ...
- python闭包和装饰器
本文目录: 1. 闭包的解析和用法 2. 函数式装饰器 3. 类装饰器 一.闭包 闭包是一种函数,从形式上来说是函数内部定义(嵌套)函数,实现函数的扩展.在开发过程中,考虑到兼容性和耦合度问题,如果想 ...
- 章节八、2-火狐的插件TryXPath
一.火狐上有一个很好用的插件TryXPath能够进行元素定位(安装) 1.打开图中标识的菜单 2.然后点击“扩展”,搜索“xpath” 3.然后安装“TryXPath” 4.安装成功后右上角x显示一个 ...
- Unity协程的坑
unity终止协程提供了 StopAllCoroutines() 和 StopCoroutines() 两个方法, 但是都只能终止该文件内的 IEnumerator. 并且具体使用有点坑, 见如下实 ...
- asp.net core自定义端口
asp.net Core 自定义端口 官方文档 aspnet内库源码: https://github.com/aspnet dotnet系统内库源码:https://github.com/dotnet ...
- selenium-确认进入了预期页面(四)
selenium确认进入了预期页面 在自动化操作中,浏览器每次进入一个新的需要,都需要确认该页面是否打开或打开的页面是否是预期的页面 需要进行确认页面后方可进行下一步操作 确认页面有很多中方法,像笔者 ...