iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >解决spring data redis的那些坑
  • 195
分享到

解决spring data redis的那些坑

2024-04-02 19:04:59 195人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录spring data Redis的那些坑1. 使用lua脚本,返回类型解析错误2. spring redis基于lettuce配置Client必须显示调用spring data

spring data redis的那些坑

spring 的ioc很少有bug,aopbug开始多起来,到了它的一些“玩具”一样的组件,bug无处不在。而且跟一般的开源框架不同,在GitHub上你报告issue,会被“这不是一个bug”强行关闭。开一博文记录,给遇到同样问题而苦恼的人歇歇脚。

1. 使用lua脚本,返回类型解析错误

背景:一般来讲,就算脚本里没有return语句,redis也是会返回执行结果,看起来就像:{“Ok” = “ok”},或者{“ok”:”ok”}。然而对于一些操作redis没有返回,或者return语句后面返回一个值,spring包了的那一层壳就会出问题。影响的包:spring封装了jedis的所有版本,包括:spring-data-redis 2.0以下的所有版本,以及使用了jedis的2.0以上版本:


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.0.0.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

这种情况下就会遇到

XXX cannot be cast to XXX

原因:DefaultScriptExecutor.java类中:


    public <T> T execute(final RedisScript<T> script, final RedisSerializer<?> argsSerializer,
            final RedisSerializer<T> resultSerializer, final List<K> keys, final Object... args) {
        return template.execute((RedisCallback<T>) connection -> {
            final ReturnType returnType = ReturnType.fromJavaType(script.getResultType()); // return type is wrong.
            final byte[][] keysAndArgs = keysAndArgs(argsSerializer, keys, args);
            final int keySize = keys != null ? keys.size() : 0;
            if (connection.isPipelined() || connection.isQueueing()) {
                // We could script load first and then do evalsha to ensure sha is present,
                // but this adds a sha1 to exec/closePipeline results. Instead, just eval
                connection.eval(scriptBytes(script), returnType, keySize, keysAndArgs);
                return null;
            }
            return eval(connection, script, returnType, keySize, keysAndArgs, resultSerializer);
        });
    }

而作为消费者,一般会将返回值设置为Object,因为同一个脚本里有若干的逻辑,不同情况下返回值可能是布尔型,字符串型,Number型等。


    ScriptSource scriptSource = new ResourceScriptSource(new ClassPathResource("META-INF/scripts/redis.lua"));
    DefaultRedisScript<Object> redisScript = new DefaultRedisScript<Object>();
    redisScript.setScriptSource(scriptSource);
    redisScript.setResultType(Object.class);

而DefaultScriptExecutor的execute方法,会把Object类型解析为List类型,进而设置returnType为Multi。


public Object convert(Object result) {
        if (result instanceof String) {
            // evalsha converts byte[] to String. Convert back for consistency
            return SafeEncoder.encode((String) result);
        }
        if (returnType == ReturnType.STATUS) {
            return JedisConverters.toString((byte[]) result);
        }
        if (returnType == ReturnType.BOOLEAN) {
            // Lua false comes back as a null bulk reply
            if (result == null) {
                return Boolean.FALSE;
            }
            return ((Long) result == 1);
        }
        if (returnType == ReturnType.MULTI) {
            List<Object> resultList = (List<Object>) result;
            List<Object> convertedResults = new ArrayList<>();
            for (Object res : resultList) {
                if (res instanceof String) {
                    // evalsha converts byte[] to String. Convert back for
                    // consistency
                    convertedResults.add(SafeEncoder.encode((String) res));
                } else {
                    convertedResults.add(res);
                }
            }
            return convertedResults;
        }
        return result;
    }

会因为result(原本只是一个Object),被解析为List,转换出了问题。此外,这里居然没有设置null的转换,难道null就不是List了。。。好在spring redis基于lettuce的实现不存在这个问题。

2. spring redis基于lettuce配置Client必须显示调用

从官方的reference看,spring的lettuce的配置只需要简单使用一个包含host、port、database、passWord等链接必须信息构造的RedisStandaloneConfiguration对象作为参数传递给LettuceConnectionFactory 的构造函数,同理连接池,然而实际使用中发现,ConnectionFactory用于建立连接的是从它的client属性获取的服务器地址等,因此必须调用afterPropertiesSet方法。

现在client信息有了,可以连接,但是连接池又未开启,尽管已经在构造器参数中指定过。受限于时间,还没有调这个点。


    LettucePoolinGClientConfiguration poolingClientConfiguration = LettucePoolingClientConfiguration.builder()
        .poolConfig(new GenericObjectPoolConfig())
        .build();

    RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(
        redisProperty.getHost(),redisProperty.getPort()
    );
    redisStandaloneConfiguration.setDatabase(redisProperty.getDatabase());

    LettuceConnectionFactory cf = new LettuceConnectionFactory(redisStandaloneConfiguration, poolingClientConfiguration);
    cf.afterPropertiesSet(); // must
    StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
    stringRedisTemplate.setConnectionFactory(cf);
    setSerializer(stringRedisTemplate);

spring data redis 的优缺点

spring-data-redis是由spring的 cache api 整合 redis 而来,它的命名规则由spring cache 的规则来定义key和对key的管理,进一步弱化redis的API。

事实上redis提供的功能已经足够强大,并且可以直接使用,同时支持灵活的分库。

spring 的 cache 功能主要由 @Cacheable @CacheEvict @CachePut 实现

  • @Cacheable 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
  • @CachePut 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用
  • @CachEvict 主要针对方法配置,能够根据一定的条件对缓存进行清空

默认情况下Spring使用CacheManagerBean 来实现,其实现有3种:EHCache,Redis,ConcurrentHashMap,默认的ConcurrentHashMap 是没有过期的。

Redis 的使用也是要自己手动调 expire ,所以暂时使用原生的 jedis ,直接调用 redis 的api

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: 解决spring data redis的那些坑

本文链接: https://www.lsjlt.com/news/135913.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 解决spring data redis的那些坑
    目录spring data redis的那些坑1. 使用lua脚本,返回类型解析错误2. spring redis基于lettuce配置Client必须显示调用spring data...
    99+
    2024-04-02
  • springboot整合spring-data-redis遇到的坑
    描述使用springboot整合redis,使用默认的序列化配置,然后使用redis-client去查询时查询不到相应的key.使用工具发现,key的前面多了\xAC\xED\x00\x05t\x00!这样一个串.而且value也是不能直观...
    99+
    2023-05-31
    spring boot data
  • 如何解决Spring data jpa @Query update的坑
    小编给大家分享一下如何解决Spring data jpa @Query update的坑,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去...
    99+
    2023-06-29
  • Python中的那些“坑”
    这里要看三组代码: # 第一组: >>>a=256 >>>b = 256 >>>a is b # 第二组: >>>a = 257 >>>b = ...
    99+
    2023-01-30
    Python
  • 解决@RequestBody搭配@Data的大坑
    @RequestBody搭配@Data的坑 如果用@Data修饰实体类,里面的属性最好不要用连续几个相同字母,如果用千万别用大写。 比如下面这个User类 @Data publi...
    99+
    2024-04-02
  • 解决Golang 中使用WaitGroup的那点坑
    sync.WaitGroup对于Golang开发者来说并不陌生,其经常作为多协程之间同步的一种机制。用好它势必会让你事半功倍,但是一旦错用将引发问题。 关于WaitGroup的使用网...
    99+
    2024-04-02
  • python3中import的那么些坑
    多模块开发时注意事项 通过from 模块 import 变量,此时相当于给一个变量赋值 import time # 相当于在本文件中创建了一个名为time变量,这个变量指向python标准库中的time模块 from time ...
    99+
    2023-01-31
    import
  • Shell中关于exit0的那些坑
    在 shell 编程中,需慎用 exit 0! 首先必须弄清楚 exit 0 不是 return 0, 区别在于 return 0 用于函数中,表示函数执行成功返回 0;而 exit...
    99+
    2024-04-02
  • 解决spring jpa中update的坑
    spring jpa中update遇到的坑 使用jpa 自己编写update语句, 遇到问题: 1.在同一个service事物中,先执行保存,在执行更新,紧接着执行查询--查询结果为...
    99+
    2024-04-02
  • 那些年踩过的Dubbo坑有哪些
    那些年踩过的Dubbo坑有哪些,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。前言微服务架构在如今的9102年已经不是什么新鲜的话题了,但是怎么做好微服务架构,却又是一个永恒...
    99+
    2023-06-19
  • spring-data-redis连接操作redis的实现
    Java连接redis的客户端有很多,其中比较常用的是Jedis. (参考:redis client) spring-data-redis则是对Jedis进行了高度封装,使用起来非常...
    99+
    2024-04-02
  • Python里那些深不见底的“坑”
    Python是一门清晰简洁的语言,如果你对一些细节不了解的话,就会掉入到那些深不见底的“坑”里,下面,我就来总结一些Python里常见的坑。 列表创建和引用 嵌套列表的创建 使用*号来创建一个嵌套的list: li = [[]...
    99+
    2023-01-31
    见底 Python
  • Spring Data默认值的错误解决
    目录源码解析修正Spring Data有很多配置的默认值,但不一定都适合你。如一个依赖Cassandra 的项目,有时写入数据后,并不能立马读到。这种错误并没有什么报错,一切都是正常...
    99+
    2023-01-17
    Spring Data默认值 Spring Data默认值配置
  • 使用Spring Data JPA的坑点记录总结
    前言Spring-data-jpa的基本介绍:JPA诞生的缘由是为了整合第三方ORM框架,建立一种标准的方式,百度百科说是JDK为了实现ORM的天下归一,目前也是在按照这个方向发展,但是还没能完全实现。在ORM框架中,Hibernate是一...
    99+
    2023-05-30
    spring data jpa
  • Java Bean转Map的那些踩坑实战
    目录一、背景二、那些坑2.0 测试对象2.1 JSON 反序列化了类型丢失2.1.1 问题复现2.2.2 问题描述2.2 BeanMap 转换属性名错误2.2.1 commons-b...
    99+
    2024-04-02
  • spring-data-redis连接操作redis的实现方法
    本篇内容介绍了“spring-data-redis连接操作redis的实现方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Java连接re...
    99+
    2023-06-20
  • 解决spring集成redisson踩过的坑
    目录spring集成redisson踩过的坑第一坑就是版本兼容问题第二个坑是设置密码问题spring整合redisson配置配置方式单节点配置standalone哨兵配置sentin...
    99+
    2024-04-02
  • 细数java for循环中的那些坑
    目录1、循环语句的几种语法2、循环中需要注意的点2.1 循环如果满足了查找的需求 break 直接跳出,不要浪费性能2.2 循环集合的时候能用for each 的尽量用for eac...
    99+
    2024-04-02
  • 解决spring-boot使用logback的大坑
    最近在写一个logback的kafka appender,无意中发现spring-boot在使用logback时的一个坑 用ConsoleAppender.java来举例,假设在lo...
    99+
    2024-04-02
  • 如何解决spring jpa中update的坑
    这篇文章主要为大家展示了“如何解决spring jpa中update的坑”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何解决spring jpa中update的坑”这篇文章吧。spring j...
    99+
    2023-06-20
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作