Java OpenResty Spring Spring Boot MySQL Redis MongoDB PostgreSQL Linux Android Nginx 面试 算法 小程序 Arthas JVM juc AQS Docker DevOps


Redis 执行 Lua 脚本抛出 StatusOutput does not support set(long) 异常

Redis Lua Spring Boot 大约 5287 字

异常信息

Caused by: org.springframework.data.redis.RedisSystemException: Unknown redis exception; nested exception is java.lang.IllegalStateException: io.lettuce.core.output.StatusOutput does not support set(long)
    at org.springframework.data.redis.FallbackExceptionTranslationStrategy.getFallback(FallbackExceptionTranslationStrategy.java:53) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:43) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:272) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.connection.lettuce.LettuceScriptingCommands.convertLettuceAccessException(LettuceScriptingCommands.java:236) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.connection.lettuce.LettuceScriptingCommands.evalSha(LettuceScriptingCommands.java:195) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.connection.DefaultedRedisConnection.evalSha(DefaultedRedisConnection.java:1530) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.connection.DefaultStringRedisConnection.evalSha(DefaultStringRedisConnection.java:1776) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151]
    at org.springframework.data.redis.core.CloseSuppressingInvocationHandler.invoke(CloseSuppressingInvocationHandler.java:61) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at com.sun.proxy.$Proxy67.evalSha(Unknown Source) ~[na:na]
    at org.springframework.data.redis.core.script.DefaultScriptExecutor.eval(DefaultScriptExecutor.java:77) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.core.script.DefaultScriptExecutor.lambda$execute$0(DefaultScriptExecutor.java:68) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:222) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:189) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:176) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.core.script.DefaultScriptExecutor.execute(DefaultScriptExecutor.java:58) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.core.script.DefaultScriptExecutor.execute(DefaultScriptExecutor.java:52) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:343) ~[spring-data-redis-2.4.5.jar:2.4.5]
    at com.example.cache.CacheApplication.run(CacheApplication.java:29) [classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:795) [spring-boot-2.4.3.jar:2.4.3]
    ... 5 common frames omitted

异常代码

private static final String UNLOCK_LUA_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
private static final Integer UNLOCK_SUCCESS_RESULT = 1;

public boolean unlock(String key, String value) {
    Integer result = stringRedisTemplate.execute(RedisScript.of(UNLOCK_LUA_SCRIPT, Integer.class), Collections.singletonList(key), value);
    return UNLOCK_SUCCESS_RESULT.equals(result);
}

原因

Redis中的integer对应Java中的Long

public enum ReturnType {

    /**
     * Returned as Boolean
     */
    BOOLEAN,

    /**
     * Returned as {@link Long}
     */
    INTEGER,

    /**
     * Returned as {@link List<Object>}
     */
    MULTI,

    /**
     * Returned as {@literal byte[]}
     */
    STATUS,

    /**
     * Returned as {@literal byte[]}
     */
    VALUE;

    /**
     * @param javaType can be {@literal null} which translates to {@link ReturnType#STATUS}.
     * @return never {@literal null}.
     */
    public static ReturnType fromJavaType(@Nullable Class<?> javaType) {

        if (javaType == null) {
            return ReturnType.STATUS;
        }

        if (ClassUtils.isAssignable(List.class, javaType)) {
            return ReturnType.MULTI;
        }

        if (ClassUtils.isAssignable(Boolean.class, javaType)) {
            return ReturnType.BOOLEAN;
        }

        if (ClassUtils.isAssignable(Long.class, javaType)) {
            return ReturnType.INTEGER;
        }

        return ReturnType.VALUE;
    }
}

修改代码

Integer改为Long

private static final String UNLOCK_LUA_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
private static final Long UNLOCK_SUCCESS_RESULT = 1L;

public boolean unlock(String key, String value) {
    Long result = stringRedisTemplate.execute(RedisScript.of(UNLOCK_LUA_SCRIPT, Long.class), Collections.singletonList(key), value);
    return UNLOCK_SUCCESS_RESULT.equals(result);
}
阅读 2296 · 发布于 2021-03-18

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb

扫描下方二维码关注公众号和小程序↓↓↓

扫描二维码关注我
昵称:
随便看看 换一批