SpringBoot+Redis+Lua

Lua脚本

  • Lua脚本在Redis中执行,避免了多次的客户端与服务器之间的通信。这可以减少网络开销,提高性能,特别是在需要执行多个Redis命令以完成一个操作时。原子性:Redis保证Lua脚本的原子性执行,无需担心竞态条件或并发问题。
  • Lua脚本可以与Redis事务一起使用,确保一系列命令的原子性执行。这允许你将多个操作视为一个单一的事务,要么全部成功,要么全部失败。
  • Lua脚本提供了一种在Redis中执行复杂操作的方法,允许你在一个脚本中组合多个Redis命令。这对于处理复杂的业务逻辑非常有用,例如计算和更新分布式计数器、实现自定义数据结构等。
  • 使用Lua脚本,你可以实现复杂的原子锁,而不仅仅是使用Redis的SETNX(set if not exists)命令。
  • 对于大批量的数据处理,Lua脚本可以减少客户端和服务器之间的往返次数,从而显著减少网络开销。
  • 通过将复杂的计算移至服务器端,可以减轻客户端的负担,降低服务器的负载。
  • Redis天生支持Lua脚本,因此不需要额外的插件或扩展。
  • Lua脚本是一种常见的脚本语言,易于编写和维护。
-- 局部变量
local age = 30-- 全局变量
name = "john"--[[数据类型:整数、浮点数、字符串、布尔值、nil
]]
local num = 42
local str = "Hello, Lua!"
local flag = true
local empty = nil
local person = { name = "John", age = 30 }--[[条件语句循环语句
]]
if age < 18 thenprint("未成年")
elseif age >= 18 and age < 65 thenprint("成年")
elseprint("老年")
endfor i = 1, 5 doprint(i)
endlocal count = 0
while count < 3 doprint("循环次数: " .. count)count = count + 1
endrepeatprint("至少执行一次")
until count > 5
-- 表数据结构,用{}定义,包含键值对,键值对可以是任何数据类型
local person = {name = "jordan",age = 23,hobbies = {"basketball","baseball"}}
print("姓名:"..person.name)
print("年龄:"..person.age)-- 模块化,通过require关键字加载-- 标准库,文件操作,网络编程,正则表达式,事件处理等,通过内置模块,如io/socket等
-- 字符串处理
local text = "Lua programming"
local sub = string.sub(text,1,3)
print(sub)-- 错误处理,使用pcall汉书来包裹可能引发异常的代码块,以捕获并处理错误,通常与assert一起使用
local success,result = pcall(function()error("出错了!")
end)if success thenprint("执行成功")
elseprint("错误信息:"..result)
end

错误返回值: Lua脚本在执行期间可能会遇到错误,例如脚本本身存在语法错误,或者在脚本中的某些操作失败。Redis执行Lua脚本后,会返回脚本的执行结果。你可以检查这个结果以查看是否有错误,通常返回值是一个特定的错误标识。例如,如果脚本执行成功,返回值通常是OK,否则会有相应的错误信息。
异常处理: 在Spring Boot应用程序中,你可以使用异常处理来捕获Redis执行脚本时可能抛出的异常。Spring Data Redis提供了一些异常类,如RedisScriptExecutionException,用于处理脚本执行期间的错误。你可以使用try-catch块来捕获这些异常并采取相应的措施,例如记录错误信息或执行备用操作。

应用场景

一、缓存更新

在缓存中存储某些数据,但需要定期或基于条件更新这些数据,同时确保在更新期间不会发生并发问题
使用Lua脚本,你可以原子性地检查数据的新鲜度,如果需要更新,可以在一个原子性操作中重新计算数据并更新缓存

local cacheKey = KEYS[1] --获取缓存键
local data = redis.call('GET',cacheKey) -- 尝试从缓存中获取数据if not data then-- 数据不在缓存中,重新计算并设置data = calculateData()redis.call('SET',cacheKey,data)
end
return data

二、原子操作

需要执行多个Redis命令作为一个原子操作,确保它们在多线程或多进程环境下不会被中断
使用Lua脚本,你可以将多个命令组合成一个原子操作,如实现分布式锁、计数器、排行榜等

local key = KEYS[1] -- 获取键名
local value = ARGV[1] -- 获取参数值
local current = redis.call('GET',key) -- 获取当前值
if not current or tonumber(current) < tonumber(value) then-- 如果当前值不存在或者新值更大,设置新值redis.call('SET',key,value)
end
-- 考虑一个计数器的场景,多个客户端需要原子性地增加计数
local key = KEYS[1]
local increment = ARGV[1]
return redis.call('INCRBY',key,increment)

三、数据处理

需要对Redis中的数据进行复杂的处理,如统计、筛选、聚合等。
使用Lua脚本,你可以在Redis中执行复杂的数据处理,而不必将数据传输到客户端进行处理,减少网络开销

local keyPattern = ARGV[1] -- 获取键名匹配模式
local keys = redis.call('KEYS',keyPattern) -- 获取匹配的键
local result = {}
for i,key in ipairs(keys) dolocal data = redis.call('GET',key) -- 获取每个键对应的数据table.insert(result,processData(data))
end
return result
--[[Lua脚本允许你在Redis服务器端执行复杂的数据处理。这减少了将数据传输到客户端进行处理的开销,并允许你在Redis中执行更复杂的逻辑,从而提高性能
]]
local total = 0
for _,key in ipairs(KEYS) dolocal value = redis.call('GET',key)total = total + tonumber(value)
end
return total

四、分布式锁

使用Lua脚本,你可以在Redis中执行复杂的数据处理,而不必将数据传输到客户端进行处理,减少网络开销
使用Lua脚本,你可以原子性地尝试获取锁,避免竞态条件,然后在完成后释放锁

local lockKey = KEYS[1] -- 获取锁的键名
local lockValue = ARGV[1] -- 获取锁的值
local lockTimeout = ARGV[2] --获取锁的超时时间
if redis.call('SET',lockKey,lockValue,'NX','PX',lockTimeout) then-- 锁获取成功,执行相关操作redis.call('DEL',lockKey)return true
elsereturn false --无法获取锁

五、事务

local key1 = KEYS[1]
local key2 = KEYS[2]
local value = ARGV[1]redis.call('SET', key1, value)
redis.call('INCRBY', key2, value)-- 如果这里的任何一步失败,整个事务将回滚

SpringBoot实现Lua脚本

Spring Data Redis和Lettuce(或Jedis)客户端的使用

一、添加依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>io.lettuce.core</groupId><artifactId>lettuce-core</artifactId> <!-- 或使用Jedis -->
</dependency>

二、application.properties或application.yml配置Redis连接

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=yourPassword

三、创建Lua脚本

myscript.lua

local a = tonumber(ARGV[1])
local b = tonumber(ARGV[2])
return a + b

四、编写代码执行Lua脚本

使用Spring Data Redis提供的StringRedisTemplate或LettuceConnectionFactory

两种不同的示例来执行Lua脚本,一种是直接运行Lua脚本字符串,另一种是运行脚本文件。

/**运行Lua脚本字符串
*/
@Service
public class LuaScriptService{@Autowiredprivate StringRedisTemplate stringRedisTemplate;public Integer executeLuaScriptFromString(){String luaScript = "local a = tonumber(ARGV[1])\nlocal b = tonumber(ARGV[2])\nreturn a + b";RedisScript<Integer> script = new DefaultRedisScript<>(luaScript,Integer.class);String[] keys = new String[0];//通常情况下,没有KEYS部分Object[] args = new Object[]{10,20};//传递给Lua脚本的参数Integer result = stringRedisTemplate.execute(script,keys,args);return result;}
}

创建一个文件myscript.lua,然后通过类运行该文件

@Service
public class LuaScriptService{@Autowiredprivate StringRedisTemplate.stringRedisTemplate;@Autowiredprivate ResourceLoader resourceLoader;public Integer executeLuaScriptFromFile(){Resource resource = resourceLoader.getResource("classpath:mysript.lua");String luaScript;try{luaScript = new String(resource.getInputStream().readAllBytes());}catch(Exception e){throw new RuntimeException("Unable to read Lua script file.");}RedisScript<Integer> script = new DefaultRedisScript<>(luaScript, Integer.class);String[] keys = new String[0]; // 通常情况下,没有KEYS部分Object[] args = new Object[]{10, 20}; // 传递给Lua脚本的参数Integer result = stringRedisTemplate.execute(script, keys, args);return result;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/143592.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

抖音短视频账号矩阵系统、短视频矩阵源码+无人直播源码开发可打包

抖音短视频账号矩阵系统、短视频矩阵源码无人直播源码开发可打包 矩阵系统源码主要有三种框架&#xff1a;Spring、Struts和Hibernate。Spring框架是一个全栈式的Java应用程序开发框架&#xff0c;提供了IOC容器、AOP、事务管理等功能。Struts框架是一个MVC架构的Web应用程序框…

selenium报错:没有打开网页或selenium.common.exceptions.NoSuchDriverException

文章目录 问题解决方法 问题 当selenium的环境配置没有问题&#xff0c;但在使用selenium访问浏览器时并没有打开网页&#xff0c;或者出现selenium.common.exceptions.NoSuchDriverException报错信息&#xff08;如下图所示&#xff09;。 以上问题可能的原因是没有配置chrom…

第三天课程 RabbitMQ

RabbitMQ 1.初识MQ 1.1.同步和异步通讯 微服务间通讯有同步和异步两种方式&#xff1a; 同步通讯&#xff1a;就像打电话&#xff0c;需要实时响应。 异步通讯&#xff1a;就像发邮件&#xff0c;不需要马上回复。 两种方式各有优劣&#xff0c;打电话可以立即得到响应&am…

[云原生案例2.3 ] Kubernetes的部署安装 【多master集群架构高可用 ---- (二进制安装部署)】

文章目录 1. Kubernetes多Master集群高可用方案1.1 多节点Master高可用的实现过程1.2 实现高可用方法 2. 新Master节点的部署2.1 前置准备2.2 系统初始化操作2.2.1 关闭防火墙、selinux和swap分区2.2.2 修改主机名&#xff0c;添加域名映射2.2.3 修改内核参数2.2.4 时间同步 2.…

批量重命名软件推荐 A Better Finder Rename 12最新 for mac

A Better Finder Rename的大量重命名选项被组织成15个直观的类别&#xff0c;涵盖了一个伟大的文件重命名器所期望的所有文本&#xff0c;字符&#xff0c;位置&#xff0c;转换和截断功能。 除此之外&#xff0c;A Better Finder Rename提供了更多高级功能&#xff0c;可以满…

ATFX汇市:10月美国名义CPI年率大降,美元指数创近三月新低

ATFX汇市&#xff1a;据美国劳工部劳动统计局数据&#xff0c;美国10月未季调CPI年率最新值3.2%&#xff0c;低于前值3.7%&#xff0c;低于预期值3.3%&#xff1b;10月未季调核心CPI年率最新值4%&#xff0c;低于前置和预期值的4.1%。名义CPI与核心CPI双双下降&#xff0c;透露…

计算机网络的发展及应用

计算机网络是计算机技术和通信技术高度发展并相互结合的产物。一方面&#xff0c;通信系统为计算机之间的数据传送提供最重要的支持&#xff1b;另一方面&#xff0c;由于计算机技术渗透到了通信领域&#xff0c;极大地提高了通信网络的性能。计算机网络的诞生和发展&#xff0…

C++什么时候使用指针(函数传参时)

在C中&#xff0c;使用指针作为函数参数可以在以下几种情况下提高效率&#xff1a; 需要修改函数外部的变量&#xff1a;当函数需要修改传递给它的变量的值时&#xff0c;使用指针比传值更高效。因为通过指针传递变量的地址&#xff0c;函数可以直接修改变量的值&#xff0c;而…

音频——解析 PCM 数据

文章目录 生成 PCM 数据16bit16bit mono16bit stereo16bit 4 channel16bit 8 channel24bit解析 PCM 数据多通道相同频率解析多通道不同频率解析程序源码生成 PCM 源码解析 PCM 源码生成 PCM 数据 对于多通道的 PCM 数据,其数据格式如下 ch0_data0 ch1_data0 ch2_data0 ch3_d…

10 小时 RTX 4090 兑换券免费送!用户调研招募中

感谢各位读者长久以来对「HyperAI超神经」的支持与关注&#xff0c;为了进一步提升公众号的品质&#xff0c;为读者提供高质量内容&#xff0c;我们计划通过问卷调研的形式收集读者的感受与建议&#xff0c;从而有针对性地对「HyperAI超神经」的内容风格、呈现形式等方面进行调…

目标检测—Yolo系列(YOLOv1/2/v3/4/5/x/6/7/8)

目标检测概述 什么是目标检测&#xff1f; 滑动窗口&#xff08;Sliding Window&#xff09; 滑动窗口的效率问题和改进 滑动窗口的效率问题&#xff1a;计算成本很大 改进思路 1&#xff1a;使用启发式算法替换暴力遍历 例如 R-CNN&#xff0c;Fast R-CNN 中使用 Selectiv…

第十六章 文件服务

第十六章 文件服务 1 FTP Server 简介 解释 文件传输协议 是 TCP/IP协议组中的协议之一logo 作用 提供文件共享服务互联网上多的媒体资源和软件资源&#xff0c;绝大部分都是通过FTP服务器传递软件包 vsftpd基础 控制端口 command 21/tcp数据端口 data 20/tcpFTP Se…

Qt数据库之QSqlQueryModel

创建数据模型&#xff1a; QSqlQueryModel *qryModel; //数据模型 qryModelnew QSqlQueryModel(this);qryModel->setQuery("SELECT empNo, Name, Gender, Height, Birthday, Mobile, Province, City, Department, "" Education, Salary FROM employee ORDE…

在 Electron上安装better-sqlite3出错

错误问题 一直卡npm install --global windows-build-tools --vs2015 这一步 解决 安装&#xff1a;pnpm install better-sqlite3 --save安装命令 pnpm i -D electron-rebuild 手动运行&#xff1a;node_modules/.bin/electron-rebuild -f -w better-sqlite3 我直接在packa…

Python武器库开发-flask篇之flask框架的安装(二十一)

Flask介绍 Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架&#xff0c;对于Werkzeug本质是Socket服务端&#xff0c;其用于接收http请求并对请求进行预处理&#xff0c;然后触发Flask框架&#xff0c;开发人员基于Flask框架提供的功能对请求进…

Stable Diffusion (version x.x) 文生图模型实践指南

前言&#xff1a;本篇博客记录使用Stable Diffusion模型进行推断时借鉴的相关资料和操作流程。 相关博客&#xff1a; 超详细&#xff01;DALL E 文生图模型实践指南 DALLE 2 文生图模型实践指南 目录 1. 环境搭建和预训练模型准备环境搭建预训练模型下载 2. 代码 1. 环境搭建…

redis基线检查

1、禁止使用 root 用户启动 | 访问控制 描述: 使用root权限来运行网络服务存在较大的风险。Nginx和Apache都有独立的work用户,而Redis没有。例如,Redis的Crackit漏洞就是利用root用户权限替换或增加authorize_keys,从而获取root登录权限。 加固建议: 使用root切换到re…

Docker - DockerFile

Docker - DockerFile DockerFile 描述 dockerfile 是用来构建docker镜像的文件&#xff01;命令参数脚本&#xff01; 构建步骤&#xff1a; 编写一个dockerfile 文件docker build 构建成为一个镜像docker run 运行脚本docker push 发布镜像&#xff08;dockerhub&#xff0…

Kyligence 入选 Gartner® 2023 客户之声报告,高分获评“卓越表现者”

近日&#xff0c;Gartner 发布了最新的《2023 分析和商业智能平台“客户之声”报告》(Voice of the Customer for Analytics and Business Intelligence Platforms, 2023, October 2023)。跬智信息&#xff08;Kyligence&#xff09;成功入选该报告&#xff0c;并凭借 4.7 分&a…

每日一题----昂贵的婚礼

#include <iostream> #include <algorithm> #include <cstring> #include <queue> #include <vector> using namespace std; //本题酋长的允诺也算一个物品,最后一定要交给酋长&#xff0c;那么等级不能超过酋长的等级范围const int N 150 * 15…