Redis有的值能存有的值不能存、Jedis不好使了?
问题来了
有的值可以存进去
有的值存不进去
是不是redis坏了?是不是Jedis 客户端不好使了。
本地测试一下:
同样的redis.conf 文件(window 和 centos)
centos 是线上
windows是本地测试
@Test public void test03(){ Jedis jedis = JedisUtil.getInstance().getJedis(); jedis.hset(Constants.GOODS_KANGO_AMOUNT,"wxg_1803271041153448","1"); jedis.hincrBy(Constants.GOODS_KANGO_AMOUNT,"wxg_1803271041153449",1L); JedisUtil.returnBrokenResource(jedis); }
结果:redis 看到了这个值。存进去了
为什么 在线上 存不进去呢 ?
解决思路
就是想看下 客户端到底干了什么
./redis-cli #输入你的密码(如果需要) auth **** #开启对客户端的监控 monitor
于是再次测试(真是逻辑。不是上面的testcase)
可以看到, 我这里是很明显 执行了 我需要的所有的 命令
但是不知道 从哪里冒出来了一个
FLUSHDB
FLUSHALL
这个是在select 1 (redis 切换 database 1)的时候 紧跟着调用的 ( redis 是串行的)
那么好的 我为什么要切换database ? 切换成 1
我想到了我用redis的地方
一些频繁操作,放redis 减少DB压力
一些数据查询,用redis 做mybatis 二级缓存。
就只有这两个地方了。
查了下mybatis的配置,果真用的是 database 1
那么好的 我需要看下源码了。为什么会执行
flushdb
flushall
这两个命令呢?
如果你要自定义你的mybatis二级缓存
你需要实现这个接口
package org.apache.ibatis.cache; import java.util.concurrent.locks.ReadWriteLock; public interface Cache { String getId(); int getSize(); void putObject(Object key, Object value); Object getObject(Object key); Object removeObject(Object key); void clear(); ReadWriteLock getReadWriteLock(); }
我的代码是这样实现的(这个也是一个网上找的类)
大家着重看下 clear() 方法
这就是造成此次问题的罪魁祸首了
public class RedisCache implements Cache { private static final Logger logger = LoggerFactory.getLogger(RedisCache.class); private static JedisConnectionFactory jedisConnectionFactory; private final String id; /** * The {@code ReadWriteLock}. */ private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public RedisCache(final String id) { if (id == null) { throw new IllegalArgumentException("Cache instances require an ID"); } logger.debug("MybatisRedisCache:id=" + id); this.id = id; } @Override public void clear() { JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); connection.flushDb(); connection.flushAll(); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } } @Override public String getId() { return this.id; } @Override public Object getObject(Object key) { Object result = null; JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); result = serializer.deserialize(connection.get(serializer.serialize(key))); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } return result; } @Override public ReadWriteLock getReadWriteLock() { return this.readWriteLock; } @Override public int getSize() { int result = 0; JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); result = Integer.valueOf(connection.dbSize().toString()); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } return result; } @Override public void putObject(Object key, Object value) { JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); connection.set(serializer.serialize(key), serializer.serialize(value)); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } } @Override public Object removeObject(Object key) { JedisConnection connection = null; Object result = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); result = connection.expire(serializer.serialize(key), 0); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } return result; } public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) { RedisCache.jedisConnectionFactory = jedisConnectionFactory; } }
那么什么时候clear()会被调用呢 ?
查看了一下 他的调用(全局搜索的)
看到这些 好熟悉,这些不就是 mybatis 对应二级缓存的一些处理策略嘛
fifo
lru
…
也就是说。我们的实现类 cn.bywind46.pc.common.RedisCache
会最终 被引入到这些 策略 中 然后执行我们的重写方法
这里面也包括了 clear();
我在一个mapper文件中配置,当前文件所有select都是用缓存
配置如下
现在明白了
缓存清理:LRU
失效时间:86400000 (毫秒)
缓存容量:2048
<cache type="cn.bywind46.pc.common.RedisCache" eviction="LRU" flushInterval="86400000" size="2048" readOnly="false"/>
OK 这很好理解了
不是时间到了
就是size到了呗
但是不对啊。时间是一天已清理。还没有到时间呢
size 我才存了几个SQL语句,不到2048个对象引用数啊。
那这是为什么呢?
继续找了一下clear()方法的调用发现了这个类
他也是调用了clear方法,在什么时候调用的呢?在事务提交的时候。
这就很好理解了,因为有事务的时候,通常是执行 写操作(insert 、update、delete)
这些时候回清缓存。了解了。回头看下代码,确实是在存入redis之前 我先做了一次update 和 insert DB 操作。
本地DEBUG看了下调用链路
(通过这个过程,也知道了,会有那些类参与这个过程(DB写操作,事务提交,缓存清理))
这一路的设计如下
好的到这里总算是找到思路了
怎么做
找到RedisCache这个类,改在下clear()方法
很简单,直接注释掉 connection.flushAll()
其他的保持不变
mybatis的缓存策略还是按照他自己的来
其他的缓存 我们放到 不同的库,这样大家都不会有干扰了
@Override public void clear() { JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); connection.flushDb(); // connection.flushAll(); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } }
重新部署下
看看结果
存储了下来。问题得以解决了
总结下
第一步查找日志或者监控
源码阅读
测试对比
断点调试,找到调用链路中可能出现问题的地方
相关推荐:https://www.roncoo.com/course/list.html?courseName=redis

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
SpringBoot项目中使用AOP
1.概述 将通用的逻辑用AOP技术实现可以极大的简化程序的编写,例如验签、鉴权等。Spring的声明式事务也是通过AOP技术实现的。 具体的代码参照示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-aop Spring的AOP技术主要有4个核心概念: Pointcut: 切点,用于定义哪个方法会被拦截,例如execution(* cn.springcamp.springaop.service.*.*(..)) Advice: 拦截到方法后要执行的动作 Aspect: 切面,把Pointcut和Advice组合在一起形成一个切面 Join Point: 在执行时Pointcut的一个实例 Weaver: 实现AOP的框架,例如 AspectJ 或 Spring AOP 2. 切点定义 常用的Pointcut定义有 execution 和@annotation两种。execution 定义对方法无侵入,用于实现比较通用的切面。@annotation可以作为注解加到特定的方法上,例如Spring的Transacti...
- 下一篇
从零到百亿互联网金融架构发展史
从零到百亿互联网金融架构发展史 回想起从公司成立敲出的第一行代码算起到现在也快三年了,平台的技术架构,技术体系也算是经历了四次比较重大的升级转化(目前第四代架构体系正在进行中),临近年底也想抽出时间来回顾一下,一个小公司从最开始的零交易到现在交易量超过百亿背后的技术变迁。 总体介绍 在互联网金融行业一百多亿其实也算不上大平台,也就是二级阵营吧,其实每次的架构升级都是随着业务重大推进而伴随的,在前一代系统架构上遇到的问题,业务开发过程中积累一些优秀的开发案例,在下一代系统开发中就会大力推进架构升级。一方面可以平滑过度,一方面公司资源可以大力支持,同时技术的小伙伴们可以使用到前沿的技术,更有开发的成就感,就这样我们大概也就是9个月就行系统架构一次升级,就到了我们现在的这套架构中。 很多网友经常会问,你们平台的TPS是多少呀,最大并发是多少呀,性能怎么样,说实话我们是一个小公司,最夸张也就上万人同时抢标,但是做为一个中型的互联网金融平台要做的事情也真的不少,远远不只是这些参数可以说的清楚;我们也不是什么高大上的平台,使用的技术也是目前比较主流开源产品,但在公司不断发展的过程中也遇到了很多的问...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS8编译安装MySQL8.0.19
- CentOS8安装Docker,最新的服务器搭配容器使用
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2全家桶,快速入门学习开发网站教程
- 2048小游戏-低调大师作品
- CentOS7设置SWAP分区,小内存服务器的救世主