RedisTemplate执行lua脚本在Redis集群模式下报错EvalSha is not supported in cluster environment.

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: RedisTemplate执行lua脚本在Redis集群模式下报错EvalSha is not supported in cluster environment.


RedisTemplate执行lua脚本在Redis集群模式下报错:EvalSha is not supported in cluster environment.

执行方法,Redis是单节点执行成功但是集群下报错

public boolean unlock(String key, String value) {
    Long result = template.execute(redisScript, Arrays.asList(key),Arrays.asList(value));
    return RELEASE_SUCCESS.equals(result);
}
org.springframework.dao.InvalidDataAccessApiUsageException: EvalSha is not supported in cluster environment.
  at org.springframework.data.redis.connection.jedis.JedisClusterScriptingCommands.evalSha(JedisClusterScriptingCommands.java:83) ~[spring-data-redis-2.1.8.RELEASE.jar:2.1.8.RELEASE]
  at org.springframework.data.redis.connection.DefaultedRedisConnection.evalSha(DefaultedRedisConnection.java:1318) ~[spring-data-redis-2.1.8.RELEASE.jar:2.1.8.RELEASE]
  at org.springframework.data.redis.connection.DefaultStringRedisConnection.evalSha(DefaultStringRedisConnection.java:1729) ~[spring-data-redis-2.1.8.RELEASE.jar:2.1.8.RELEASE]
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_181]
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_181]
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_181]
  at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_181]
  at org.springframework.data.redis.core.CloseSuppressingInvocationHandler.invoke(CloseSuppressingInvocationHandler.java:61) ~[spring-data-redis-2.1.8.RELEASE.jar:2.1.8.RELEASE]
  at com.sun.proxy.$Proxy196.evalSha(Unknown Source) ~[?:?]

原因

RedisTemplate默认情况下拿到的connection是单机的

解决

集群模式直接抛出不支持执行脚本的异常,因为只能拿到原redis的connection来执行脚本

public boolean unlock(String key, String value) {
     //使用Lua脚本:先判断是否是自己设置的锁,再执行删除
     // 使用lua脚本删除redis中匹配value的key,可以避免由于方法执行时间过长而redis锁自动过期失效的时候误删其他线程的锁
     // spring自带的执行脚本方法中,集群模式直接抛出不支持执行脚本的异常,所以只能拿到原redis的connection来执行脚本
     List<String> keys = new ArrayList<>();
     keys.add(key);
     List<String> args = new ArrayList<>();
     args.add(value);
     Long result = template.execute(new RedisCallback<Long>() {
         @Override
         public Long doInRedis(RedisConnection connection) throws DataAccessException {
             Object nativeConnection = connection.getNativeConnection();
             // 集群模式和单机模式虽然执行脚本的方法一样,但是没有共同的接口,所以只能分开执行
             // 集群模式
             if (nativeConnection instanceof JedisCluster) {
                 return (Long) ((JedisCluster) nativeConnection).eval(UNLOCK_LUA, keys, args);
             }
             // 单机模式
             else if (nativeConnection instanceof Jedis) {
                 return (Long) ((Jedis) nativeConnection).eval(UNLOCK_LUA, keys, args);
             }
             return 0L;
         }
     });
     //返回最终结果
     return RELEASE_SUCCESS.equals(result);
 }

@Resource
StringRedisTemplate stringRedisTemplate;
public Object exec(RedisScript script, List<String>keys,Object... args){
// 将可变参转为 List
    List<String> list = new ArrayList<>();
    for (Object arg : args) {
        list.add(arg.toString());
    }
    // 将 RedisScript 转换为 string 类型的脚本
    String scriptScriptAsString = script.getScriptAsString();
    return stringRedisTemplate.execute((RedisCallback<Object>) connection -> {
// 获取连接
        Object nativeConnection = connection.getNativeConnection();
        // 集群模式的实例
        if (nativeConnection instanceof JedisCluster) {
            return (Long)((JedisCluster) nativeConnection).eval(scriptScriptAsString, keys, list);
        }
        // 单机模式的实例
        if (nativeConnection instanceof Jedis) {
            return (Long)((Jedis) nativeConnection).eval(scriptScriptAsString, keys, list);
        }
        return null;
    });
}


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
NoSQL Redis
Redis 执行 Lua保证原子性原理
Redis 执行 Lua 保证原子性原理
129 1
|
2月前
|
存储 NoSQL 算法
深入理解Redis分片Cluster原理
本文深入探讨了Redis Cluster的分片原理,作为Redis官方提供的高可用性和高性能解决方案,Redis Cluster通过数据分片和横向扩展能力,有效降低单个主节点的压力。
深入理解Redis分片Cluster原理
|
2月前
|
NoSQL Java Redis
【Azure Webjob + Redis】WebJob一直链接Azure Redis一直报错 Timeout Exception
【Azure Webjob + Redis】WebJob一直链接Azure Redis一直报错 Timeout Exception
|
2月前
|
缓存 NoSQL 网络协议
【Azure Redis 缓存】Azure Redis Cluster 在增加分片数时失败分析
【Azure Redis 缓存】Azure Redis Cluster 在增加分片数时失败分析
|
2月前
|
缓存 NoSQL Redis
【Azure Redis 缓存】Windows版创建 Redis Cluster 实验 (精简版)
【Azure Redis 缓存】Windows版创建 Redis Cluster 实验 (精简版)
|
2月前
|
存储 NoSQL Redis
Tair的发展问题之在Redis集群模式下,Lua脚本操作key面临什么问题,如何解决
Tair的发展问题之在Redis集群模式下,Lua脚本操作key面临什么问题,如何解决
|
2月前
|
NoSQL Redis
Redis——单机迁移cluster集群如何快速迁移
Redis——单机迁移cluster集群如何快速迁移
49 0
|
3月前
|
NoSQL Redis 数据安全/隐私保护
redis 常见报错和解决方案
redis 常见报错和解决方案
59 1
|
21天前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
2月前
|
缓存 NoSQL Java
Redis深度解析:解锁高性能缓存的终极武器,让你的应用飞起来
【8月更文挑战第29天】本文从基本概念入手,通过实战示例、原理解析和高级使用技巧,全面讲解Redis这一高性能键值对数据库。Redis基于内存存储,支持多种数据结构,如字符串、列表和哈希表等,常用于数据库、缓存及消息队列。文中详细介绍了如何在Spring Boot项目中集成Redis,并展示了其工作原理、缓存实现方法及高级特性,如事务、发布/订阅、Lua脚本和集群等,帮助读者从入门到精通Redis,大幅提升应用性能与可扩展性。
60 0
下一篇
无影云桌面