【redis事务】@Transactional对Redis事务起作用(包含redis+lua)

news2024/11/25 0:24:56

【redis事务】@Transactional对Redis事务起作用(包含redis+lua)

    • 一、前言
    • 二、准备
    • 三、StringRedisTemplate 开启事务
    • 四、关键代码(验证@Transactional对redis事务是否生效)
    • 五、关键代码(验证@Transactional对redis+lua是否生效)

一、前言

最近工作中涉及到的事务比较多,也有用到redis事务,之前的文章也介绍过redis事务,为了方便redis使用,我们把redis事务结合springboot的@Transactional注解使用,这里为了方便大家使用,写一个demo验证一下;

注:同时也验证一下redis+lua脚本执行中,@Transactional注解事务是否生效

二、准备

为了对比事务,我们同时使用数据库(postgresql)事务redis事务

引入pom.xml依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <!-- postgresql 配置-->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>

三、StringRedisTemplate 开启事务

package com.sk.config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;

@Configuration
@RequiredArgsConstructor
public class RedisConfig {

    private final StringRedisTemplate stringRedisTemplate;

    @Bean
    public void getRedisTemplate(){
        stringRedisTemplate.setEnableTransactionSupport(true);
    }

}

四、关键代码(验证@Transactional对redis事务是否生效)

1、正常执行

package com.sk.service.impl;

import com.sk.mapper.StudentMapper;
import com.sk.service.AnimalService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("dogService")
@RequiredArgsConstructor
//@ConditionalOnProperty(prefix = "formatter",name="enabled",havingValue = "true")
public class DogServiceImpl implements AnimalService {

    private final StringRedisTemplate stringRedisTemplate;

    private final StudentMapper studentMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void play() {

        System.out.println("狗拿耗子!!!");
        boolean insert = studentMapper.insertUser(3,"刘英","男","123456","");
        System.out.println("pg插入结果:"+insert);
        stringRedisTemplate.opsForValue().set("3","liuying");
        System.out.println("==========执行完成======");
        //throw new RuntimeException("redis事务测试");
    }

    @Override
    public void eat() {
        System.out.println("狗爱吃骨头!!!");
    }
}

执行结果:

2022-12-11 11:46:37.268  INFO 9752 --- [nio-8089-exec-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
狗拿耗子!!!
pg插入结果:true
==========执行完成======

在这里插入图片描述

127.0.0.1:6379> get 3
"liuying"
127.0.0.1:6379> 
127.0.0.1:6379> 
127.0.0.1:6379> 

2、事务回滚

package com.sk.service.impl;

import com.sk.mapper.StudentMapper;
import com.sk.service.AnimalService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("dogService")
@RequiredArgsConstructor
//@ConditionalOnProperty(prefix = "formatter",name="enabled",havingValue = "true")
public class DogServiceImpl implements AnimalService {

    private final StringRedisTemplate stringRedisTemplate;

    private final StudentMapper studentMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void play() {

        System.out.println("狗拿耗子!!!");
        boolean insert = studentMapper.insertUser(3,"刘英","男","123456","");
        System.out.println("pg插入结果:"+insert);
        stringRedisTemplate.opsForValue().set("3","liuying");
        System.out.println("==========执行完成======");
        throw new RuntimeException("redis事务测试");
    }

    @Override
    public void eat() {
        System.out.println("狗爱吃骨头!!!");
    }
}

执行结果

2022-12-11 11:51:28.699  INFO 12864 --- [nio-8089-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
狗拿耗子!!!
pg插入结果:true
==========执行完成======
2022-12-11 11:51:29.978 ERROR 12864 --- [nio-8089-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: redis事务测试] with root cause

java.lang.RuntimeException: redis事务测试
	at com.sk.service.impl.DogServiceImpl.play(DogServiceImpl.java:28) ~[classes/:na]
	at com.sk.service.impl.DogServiceImpl$$FastClassBySpringCGLIB$$6e845405.invoke(<generated>) ~[classes/:na]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.23.jar:5.3.23]

在这里插入图片描述

127.0.0.1:6379> get 5
(nil)
127.0.0.1:6379> 
127.0.0.1:6379> 

由结果可知,pg数据库redis中数据并没有存储成功,证明事务生效;

五、关键代码(验证@Transactional对redis+lua是否生效)

1、lua脚本:

local key = KEYS[1]
redis.call("INCR",key);

2、初始化lua脚本:

/**
     * 读取限流脚本
     *
     * @return
     */
    @Bean
    public DefaultRedisScript<Number> redisluaScript() {
        DefaultRedisScript<Number> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/test.lua")));
        redisScript.setResultType(Number.class);
        return redisScript;
    }

3、正常执行

package com.sk.service.impl;

import com.sk.mapper.StudentMapper;
import com.sk.service.AnimalService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service("dogService")
@RequiredArgsConstructor
//@ConditionalOnProperty(prefix = "formatter",name="enabled",havingValue = "true")
public class DogServiceImpl implements AnimalService {

    private final StringRedisTemplate stringRedisTemplate;

    private final StudentMapper studentMapper;

    private final DefaultRedisScript defaultRedisScript;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void play() {
        System.out.println("执行lua脚本");
        List<String> keys = new ArrayList();
        keys.add("count");
        stringRedisTemplate.execute(defaultRedisScript, keys);
        System.out.println("==========执行完成======");
        //throw new RuntimeException("redis事务测试");
    }

    @Override
    public void eat() {
        System.out.println("狗爱吃骨头!!!");
    }
}

执行结果

127.0.0.1:6379> get count
"1"
127.0.0.1:6379> 
127.0.0.1:6379> 

4、执行失败

package com.sk.service.impl;

import com.sk.mapper.StudentMapper;
import com.sk.service.AnimalService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service("dogService")
@RequiredArgsConstructor
//@ConditionalOnProperty(prefix = "formatter",name="enabled",havingValue = "true")
public class DogServiceImpl implements AnimalService {

    private final StringRedisTemplate stringRedisTemplate;

    //private final StudentMapper studentMapper;

    private final DefaultRedisScript defaultRedisScript;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void play() {
        System.out.println("执行lua脚本");
        List<String> keys = new ArrayList();
        keys.add("count");
        stringRedisTemplate.execute(defaultRedisScript, keys);
        System.out.println("==========执行完成======");
        throw new RuntimeException("redis事务测试");
    }

    @Override
    public void eat() {
        System.out.println("狗爱吃骨头!!!");
    }
}

执行结果

执行lua脚本

==========执行完成======
2022-12-11 12:19:33.272 ERROR 12736 --- [nio-8089-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: redis事务测试] with root cause

java.lang.RuntimeException: redis事务测试
	at com.sk.service.impl.DogServiceImpl.play(DogServiceImpl.java:39) ~[classes/:na]
127.0.0.1:6379> get count
"1"
127.0.0.1:6379> 
127.0.0.1:6379> 

由上可知,当程序执行异常时,lua脚本中的内容同样没有生效

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

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

相关文章

回顾Redis之对象与数据结构

引言 Redis是一款基于键值对的数据结构存储系统&#xff0c;它的特点是基于内存操作、单线程处理命令、IO多路复用模型处理网络请求、键值对存储与简单丰富的数据结构等等 这篇文章主要围绕Redis中的对象与数据结构来详细说明键值对存储与简单丰富的数据结构这两大特点 Redi…

CSS 实现一个3d魔方

前言 &#x1f44f;CSS 实现一个3d魔方&#xff0c;速速来Get吧~ &#x1f947;文末分享源代码。记得点赞关注收藏&#xff01; 1.实现效果 2.实现步骤 魔方的一面为九个圆角正方形&#xff0c;定义正方形的宽高为–w&#xff0c;九个正方形的直接的间距为–gap&#xff0c;…

Spring整合其他技术

Spring整合其他技术 1 Spring整合mybatis 1.1 思路分析 问题导入 mybatis进行数据层操作的核心对象是谁&#xff1f; 1.1.1 MyBatis程序核心对象分析 1.1.2 整合MyBatis 使用SqlSessionFactoryBean封装SqlSessionFactory需要的环境信息 使用MapperScannerConfigurer加载…

安卓玩机搞机技巧综合资源----手机显秒设置 多种方式【十一】

接上篇 安卓玩机搞机技巧综合资源------如何提取手机分区 小米机型代码分享等等 【一】 安卓玩机搞机技巧综合资源------开机英文提示解决dm-verity corruption your device is corrupt. 设备内部报错 AB分区等等【二】 安卓玩机搞机技巧综合资源------EROFS分区格式 小米红…

电子学会2020年9月青少年软件编程(图形化)等级考试试卷(二级)答案解析

目录 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 二、判断题&#xff08;共10题&#xff0c;每题2分&#xff0c;共20分&#xff09; 三、编程题【该题由测评师线下评分】&#xff08;共2题&#xff0c;共30分&#xff09; 青少年软件…

软件安全设计(威胁建模实现)

目录 一、实验目的 二、实验软硬件要求 三、实验预习 四、实验内容&#xff08;实验步骤、测试数据等&#xff09; 实验步骤 确定安全目标 创建在线学习系统概况图 分解在线学习系统 确定威胁 威胁评估 确定威胁缓解计划或策略 验证和记录威胁 一、实验目的 熟悉软…

[附源码]JAVA毕业设计医院管理系统(系统+LW)

[附源码]JAVA毕业设计医院管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&…

Spring Cloud Feign的自定义配置及使用

Feign 提供了很多的扩展机制&#xff0c;让用户可以更加灵活的使用&#xff0c;这节我们来学习 Feign 的一些自定义配置。 日志配置 有时候我们遇到 Bug&#xff0c;比如接口调用失败、参数没收到等问题&#xff0c;或者想看看调用性能&#xff0c;就需要配置 Feign 的日志了…

遥感影像(tif,img)概览/金字塔(overviews)的创建与清除

使用python环境下的gdal进行遥感影像&#xff08;tif&#xff0c;img格式&#xff09;概览&#xff08;overviews&#xff09;的创建与清除&#xff0c;前边是测试过程&#xff0c;结论在最后 过程 问题起因是拿到一批img格式的影像需要转cog&#xff0c;程序运行中报了个错 …

ESXi8.0安装,实体机安装,IPMI远程安装实战笔记

目录 1.前言 2.连接主板IMPI 3.硬件兼容及BIOS设置 4.从U盘安装ESXi ESXi8.0安装包下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1-a3ka1TAScFPtAc29jcxzQ 提取码&#xff1a;qwhg 1.前言 ESXi系列的虚拟机直接以操作系统的形态出现&#xff0c;与基于Li…

【Linux静态库和动态库】

Linux静态库和动态库1. 编译与ELF格式2. 库的基本概念3.静态库的制作&#xff1a;&#xff08;假设要将a.c、b.c制作成静态库&#xff09;4.静态库的常见操作5.静态库的使用6. 多个库的相互依赖举例1.(库文件制作、错误处理)7.静态库和动态库的关系和区别8.动态库的制作软链接 …

ADI Blackfin DSP处理器-BF533的开发详解25:USB接口设计(含源代码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 硬件设计原理图 功能介绍 跟网口一样&#xff0c;USB这个设计很勉强&#xff0c;因为BF533并不带USB口&#xff0c;当时是给一个大厂做MP4的方案…

猿如意中的【UltraEdit】开发工具详情介绍

目录 一、工具名称 二、下载安装渠道 2.1 什么是猿如意&#xff1f; 2.2 如何下载猿如意&#xff1f; 2.3 如何在猿如意中下载UltraEdit&#xff1f; 三、UltraEdit介绍 四、软件安装过程 五、软件界面 六、UltraEdit功能特点介绍 七、UltraEdit使用/体验感受…

Python测试进阶(二)

文章目录简介selenium等待Web控件交互表单操作多窗口frame多浏览器处理用 js 操作文件上传弹窗pageObject复用浏览器简介 这部分主要介绍 web 自动化测试 selenium 专门测试 web 的工具&#xff0c;根据测试用例&#xff0c;直接在浏览器上执行对应动作还是在 pytest 框架中…

牛客网SQL入门复健小练

SQL3&#xff1a;distinct 查询结果去重&#xff0c;返回所有不同的university 方法一&#xff1a;distinct关键字。&#xff08;注意&#xff1a;这个关键字实际上是 select distinct&#xff0c;如果是多列&#xff0c;多列作为一个组合然后 distinct 去重&#xff09; 方…

[oeasy]python0028_直接运行_修改py文件执行权限_设置py文件打开方式

直接运行 回忆上次内容 我们把两个程序整合起来了 可以持续输出当前时间每秒都更新但是我想在 shell 里面 只输入文件名(./sleep.py)并回车就能不断输出时间可能吗&#xff1f;&#x1f914; import time while True:print(time.asctime())time.sleep(1) 尝试执行 第 1 句 根…

EXCEL基础:数据透视表(按月或月累计统计操作)

【按月统计数据】&#xff1a; 本操作实现的是原始数据是以日为单位&#xff0c;统计使用的时候&#xff0c;需要以月份或者季度、年份的形式进行&#xff0c;可以使用数据透视表的【组合】功能来 实现&#xff0c;如下所示&#xff1a; 如下所示&#xff0c;将日期字段放在行…

免费分享一套基于VuePress开发的markdown产品文档

vuepress-theme-jingli 文档 | 效果 | 本仓库的gitee镜像 &#xff08;进入赞助商扫码注册可为本项目作者充电~&#xff09; 介绍 这个主题的初衷是打造一个好用的、面向程序员的知识管理工具轻松构建一个结构化的知识库&#xff0c;让你的知识海洋像一本本书一样清晰易读。…

Mac 下设置VScode 背景图片失败解法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言解法一&#xff1a;直接修改VScode 的CSS解法二&#xff1a;还是想用插件总结前言 仓库推荐 C/C 每日一练小仓库&#xff0c;慢慢学习C 知识必备仓库 https://…

Java8:SPI机制

参考资料&#xff1a; 《双亲委派机制及其弊端》 《Java中SPI机制深入及源码解析》 《Java SPI思想梳理》 《深入理解 Java 中 SPI 机制》 写在开头&#xff1a;本文为学习后的总结&#xff0c;可能有不到位的地方&#xff0c;错误的地方&#xff0c;欢迎各位指正。 目录 …