Redis实现Lua脚本

最近在做某项目时,遇到了一种场景:从Redis中读取数据,进行数据处理后,删除该数据。乍一看好像没什么问题。但是把该场景扩展到多线程,多应用同时执行时,可能会导致重复读取相同数据,并进行处理的场景。因此,为了实现Redis原子性操作数据,决定引入Redis中的Lua脚本来执行数据读取,数据处理和数据删除操作。

1、Redis Lua脚本介绍

Lua是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放。其设计目的就是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。因为广泛的应用于:游戏开发、独立应用脚本、Web 应用脚本、扩展和数据库插件等。
使用Lua脚本的好处如下:
(1)、减少网络开销。可以将多个请求通过脚本的形式一次发送,减少网络时延。
(2)、原子操作。Redis会将整个脚本作为一个整体执行,中间不会被其他请求插入。因此在脚本运行过程中无需担心会出现竞态条件,无需使用事务。
(3)、复用。客户端发送的脚本会永久存在redis中,这样其他客户端可以复用这一脚本,而不需要使用代码完成相同的逻辑。
Lua命令不多,主要是下面这几个:

  • EVAL
  • EVALSHA
  • SCRIPT LOAD – SCRIPT EXISTS
  • SCRIPT FLUSH
  • SCRIPT KILL

相关命令使用可参考:Lua 脚本Lua教程
本文不详细说明。

2、SpringBoot实现Lua脚本

  1. 引入依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
复制代码
  1. 代码示例

@Autowired
private RedisTemplate<String,Object> redisTemplate;

public List<Object> getDataAndDel(String key, String value) {
    //Lua脚本
    String redisLua = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    
    //Redis key值
    String redisKey = "REDIS_KEY_LUA_TEST";
    
    long nowTimeMs = System.currentTimesMillis();
	
    List<String> keys = Collections.singletonList(redisKey);
    List<String> argv = Collections.singletonList(String.valueOf(nowTimeMs));

    List<Object> datas = redisTemplate.execute(new RedisCallback<Long>() {
        @Override
        public List<Object> doInRedis(RedisConnection connection) throws DataAccessException {
            Object obj = connection.getNativeConnection();

            if (obj instanceof JedisCluster) {
		// 集群模式
                return (List<Object>) ((JedisCluster) obj).eval(redisLua, keys, argv);
            } else (obj instanceof Jedis) {
		/单机模式,若Redis为集群,则可去掉
                return (List<Object>) ((Jedis) obj).eval(redisLua, keys, argv);
            }
        }
    });
    return datas;
}
复制代码

说明:Redis Lua脚本最好在Redis命令行里测试正确后,在用java编写执行。

3、参考文档:

Lua 脚本

Redis中使用Lua脚本

SpringBoot+Redis执行lua脚本的方法步骤

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

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享