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

2023-11-16

一、前言

最近工作中涉及到的事务比较多,也有用到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脚本中的内容同样没有生效

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【redis事务】@Transactional对Redis事务起作用(包含redis+lua) 的相关文章

随机推荐

  • STM32开发——简介、开发环境(Keil5、CubeMX)、HAL库

    目录 1 简介 初识STM32 2 开发环境 2 1使用Keil5 2 2使用STM32CubeMX 3 标准库与HAL库区别 4 推挽输出与开漏输出 1 简介 初识STM32 什么是单片机 单片机 Single Chip Microcom
  • STM32CubeMX 生成工程步骤图文说明

    本文也适合STM32CubeMX 支持的所有芯片的设置 调整文章结构 添加图文说明 2022 2 增加其他应用章节 增加 ADC 设置说明 2023 3 考虑到增加的内容越来越多 修改文章标题 增加PWM设置说明 2023 4 增加 DAC
  • 2023年美国大学生数学建模MCM问题Y:了解二手帆船的价格-解题思路及代码分享

    2023 MCM Problem Y Understanding Used Sailboat Prices 2023年MCM问题Y 了解二手帆船的价格 和许多奢侈品一样 帆船的价值会随着老化和市场条件的变化而变化 附件中所附的 2023 M
  • 变分贝叶斯variable bayes 和EM算法关系

    https blog csdn net weixin 30851409 article details 98905998
  • angular调用应用浏览器(如微信)内置api

    由于浏览器内置api的对象是在具体应用浏览器运行时注册生成的 因此如果不在代码中处理会过不了编译 对于angular 可以采取添加 ts ignore 来忽略 innerApi为非声明的对象 ts ignore innerAPI openW
  • 时序预测

    时序预测 MATLAB实现SO ELM蛇群算法优化极限学习机时间序列预测 目录 时序预测 MATLAB实现SO ELM蛇群算法优化极限学习机时间序列预测 效果一览 基本介绍 程序设计 学习总结 参考资料 效果一览 基本介绍 Matlab实现
  • C++中的友元函数

    什么是友元函数 友元函数 与成员函数相对 是定义在类外部 可以访问该类中的所有私有 private 成员和保护 protected 成员 指定函数为某个类的友元函数的方法是使用关键字friend friend lt 返回类型 gt lt 函
  • 华为od机试题1 真题

    华为od机试题 真题 86 射击比赛成绩排序 85 计算屏幕字母数量 84 组成最大数字 82 输出字符串中最小数字 81 数字4的个数 80 整数排列 79 多条件排列 78 时间排序 以下题目附带Java解法 是我个人写的 不一定是标准
  • vue新ref语法糖争议

    近日 Vue 发明人尤雨溪在 Vue RFCs 下提交了一份新的 Ref 语法糖提案 该提案一经发布便引来了不少争议 提案内容 这份提案就是在单文件组织 SFC 中引入一个新的script 标签写法 写法为 关于为什么这样做 尤雨溪表示 一
  • 基于EEGLAB的ICA分析

    目录 1 ICA原理 2 ICA的实现 3 ICA成分识别 4 ICLabel识别并去除伪迹 5 ICA成分识别练习 1 ICA原理 得到的每一个地形图 实际上就是它的权重谱 投射 根据原成分恢复原始信号 选择性投射 去伪 2 ICA的实现
  • java Comparator 多个字段比较

    List 中元素需要排序时 需要比较元素值 当元素是复杂对象时 有时需要根据多个字段进行排序 package com example demo domain import lombok Getter import lombok NoArgs
  • 八十九.计数排序、基数排序(查找与排序(四))——JAVA

    查找与排序 一 查找与排序 二 查找与排序 三 计数排序 一句话 用辅助数组对数组中出现的数字计数 元素转下标 下标转元素 步骤 1 找出原数组中元素值最大的 记为max 2 创建一个新数组helper其长度是max加1 其元素默认值都为0
  • Linux bluez蓝牙开发的准备工作

    最近为了搞这个蓝牙的事情 忙碌了好几天 我就是想结合 bluez 的代码随便玩一下蓝牙设备 而且能够参考源码写点测试程序来操作这个蓝牙设备 这里只是说明 Linux 下的准备工作而非嵌入式的arm 1 系统支持 我用的是真机安装的 Debi
  • springboot:整合rabbitmq之重试机制

    当我们消息消费失败的时候 可以进行重试 什么情况下会重发消息 1 网络抖动 2 程序抛出异常没有try catch RabbitMQ自动补偿机制触发 多用于调用第三方接口 1 当我们的消费者在处理我们的消息的时候 程序抛出异常情况下 默认无
  • FFmpeg测试视频的实时码流(音视频学习笔记五)

    前言 这篇博文记录一个简单的实时码流测试程序 事实上FFmpeg打开媒体文件后就可以获得整个视频的平均码流 只计算视频码流 但是无法获取实时码流 因为后面的工作需要对编解码做一些优化 需要实时观测码流 这里先实现一个比较简单的版本 运行结果
  • 简单的控制台学生信息系统

    package studentsystem import java util ArrayList import java util Scanner public class APP ArrayList
  • 华为OD机试 - 英文输入法 - 逻辑分析(Java 2023 B卷 100分)

    目录 专栏导读 一 题目描述 1 需求如下 2 注意 二 输入描述 三 输出描述 四 解题思路 五 Java算法源码 六 效果展示 1 输入 2 输出 3 说明 4 区分大小写 如果联想不到 输出前缀 华为OD机试 2023B卷题库疯狂收录
  • tms xdata开发连接sqlite数据库的rest server

    1 使用向导 2 设置fdconnection的连接属性 3 设置授权 否则服务无法运行 4 运行tms data modeler 工具 5 将刚刚生成的unipersons pas文件加入到工程中 6 结果
  • 互联网摸鱼日报(2023-07-20)

    互联网摸鱼日报 2023 07 20 InfoQ 热门话题 龙蜥操作系统重磅更新 全面支持智能计算 兼容主流AI框架 微软赢麻了 联合Meta 重磅发布开源 可直接商用大模型Llama 2 网友 OpenAI 感觉如何 ChatGPT 提效
  • 【redis事务】@Transactional对Redis事务起作用(包含redis+lua)

    redis事务 Transactional对Redis事务起作用 包含redis lua 一 前言 二 准备 三 StringRedisTemplate 开启事务 四 关键代码 验证 Transactional对redis事务是否生效 五