首页 > 数据库 >【Redis】SpringBoot集成Redis事务-亲测

【Redis】SpringBoot集成Redis事务-亲测

时间:2023-09-25 10:14:42浏览次数:37  
标签:回滚 SpringBoot Redis 事务 报错 template redisTemplate 亲测

大家好,我是mep。今天一起来探讨一下Redis缓存的问题,SpringBoot如何集成Redis网上文章很多,基本都是介绍如何配置redisTemplate,如何调用,本文就不过多介绍了。这次我们研究的是:Redis的事务。

首先抛出一个问题,Redis支持事务吗?

 

 

答案肯定是支持,不然也不需要我们在这里探讨了。

然后你拿到关键词"Redis 事务"去搜索引擎搜索一下,得到了这样的答案:

Redis支持事务,But!Redis的事务不保证原子性,事务不会回滚。例如:我在Redis中提交了一个事务,包含3条命令,其中第2条命令报错了,并不会导致第一条命令的回滚,也不会阻止第三条命令的执行。

可是,真的是这样吗?你试过吗?哈哈,知道你懒得试,我来帮你们试试看喽!

先看一个我自己测试的例子,以下例子中RedisTemplate都开启了事务支持,否则测试没有意义,我的RedisConfiguration代码如下:

@Configuration
public class RedisConfiguration {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setEnableTransactionSupport(true);
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
}

然后让我们来看几个例子:

例1,使用@Transactional注解,方法执行过程中报错,代码如下:

    @Transactional
    public void testRedisTransaction() {
        employeeMapper.updateByPrimaryKey(Employee.builder()
                        .id(4L)
                        .name("uuuuu")
                        .gender(Gender.MALE)
                .build());
        redisTemplate.opsForValue().set("111", "111");
        int i = 1 / 0;
        redisTemplate.opsForValue().set("222", "111");
    }

执行前Redis缓存情况:

执行以上方法后,肯定会报错:

java.lang.ArithmeticException: / by zero

猜猜执行完后数据库和Redis中数据操作是什么样的?

 

1.数据库会回滚,即update无效,这个并不意外,没啥可说的

2.执行后Redis缓存情况:

 空的?不是说Redis的事务不支持回滚吗?为什么key修改却无效了呢?

确实,因为Redis根本没有回滚,它的事务压根就没有提交!!!

这就是Redis的事务和关系型数据库不一样的地方,数据库一个事务中如果某一条SQL报错或方法中有RuntimeException(@Transactional默认)抛出的话,事务会回滚。对于Redis的事务来说,如果方法中抛RuntimeException的话,事务压根不提交,被DISCARD之后,自然不会执行。

如果你看到这里了,说明你一开始就质疑最上面搜索到的结果,连查到的知识都会质疑和验证,为什么要相信我上面说的事务压根就没有提交的结论呢?

带着疑问,我们继续验证,先上代码:

    @Transactional
    public void testRedisTransaction() {
        employeeMapper.updateByPrimaryKey(Employee.builder()
                .id(4L)
                .name("uuuuu")
                .gender(Gender.MALE)
                .build());
        System.out.println(1234);
        redisTemplate.opsForValue().set("111", "a");
        redisTemplate.opsForValue().set("222", "a");
        redisTemplate.exec();
        int i = 1 / 0;
    }

这次主动在报异常前提交了Redis事务,结果如下:

 到这里,我们得到结论是这样的:

Redis事务不能回滚,方法报异常时事务并没有回滚,之所以数据没有被写入到Redis,是因为事务被DISCARD了

根据我们查到的内容,还需要验证Redis的事务不能保证原子性,继续上示例: 

例2,使用@Transactional注解,在Redis事务中报错,代码如下:

    @Transactional
    public void testRedisTransactionOnly() {
        redisTemplate.opsForValue().set("333", "a");
        redisTemplate.opsForHash().put("333", "a", 111);
    }

正常来说,应该会报WRONGTYPE Operation的错误,不过,执行结果是这样的:

 甚至,连个错误都没有报!

是代码的问题吗?还是因为Redis的事务忽略了异常的命令,只执行了正常的命令?

继续测试,清空Redis,去掉@Transactional注解:

//    @Transactional
    public void testRedisTransactionOnly() {
        redisTemplate.opsForValue().set("333", "a");
        redisTemplate.opsForHash().put("333", "a", 111);
    }

执行结果:

 可见代码没有问题,确实会报错,只是提交到一个事务中,它不保证原子性,只执行了可执行的命令,即使后续的命令报错,也不会回滚,而且不会报错

至此,Redis事务相关的验证已结束。

结论就是我们开始搜索到的结果:

Redis支持事务,But!Redis的事务不保证原子性,事务不会回滚,提交后会执行可正常执行的命令,忽略报错的命令。

最后,来自Redis官网的一句话佐证我们的结论, 附出处:Transactions | Redis

标签:回滚,SpringBoot,Redis,事务,报错,template,redisTemplate,亲测
From: https://www.cnblogs.com/maerpao/p/17705258.html

相关文章

  • SpringBoot发送带文件的Post请求
    使用httpclient发送一个带文件参数的Post请求Pom依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.apac......
  • Vite+ts+springboot项目集成2
    项目集成集成element-plus官网地址:安装图标库pnpminstallelement-plus@element-plus/icons-vue入口文件main.ts全局安装element-plus,element-plus默认支持语言英语设置为中文importElementPlusfrom'element-plus';import'element-plus/dist/index.css'//@ts-ig......
  • NoSQL之Redis配置与优化
    目录NoSQL之Redis配置与优化1.关系数据库和非关系型数据库2.SQL与NoSQL的区别3.Redis3.1Redis概述问题3.2Redis为什么那么快?3.3Redis安装部署3.3.1环境准备3.3.2修改内核参数3.3.3安装redis3.3.4修改配置文件3.3.5定义systemd服务管理脚本3.4Redis命令工具3.4.1......
  • springBoot结合springcloud alibaba
    版本对应很重要,很多问题都源于版本没有对应Q1:SpringCloud启动报错Didyouforgettoincludespring-cloud-starter-loadbalancerQ2:Nacos集群出现NacosException:Clientnotconnected,currentstatus:STARTINGQ3:配置中心不生效Q4:Errorcreatingbeanwithname‘configDataConte......
  • Redis源码分析之启动流程
    源码版本:5.0图形工具:http://www.plantuml.com/plantuml/uml时序图源码:@startumlgroupmainserver.c->setproctitle.c:spt_init():为函数setproctitle调用做初始化工作server.c->server.c:setlocale(LC_COLLATE,"");server.c->server.c:tzset();......
  • golang 使用redis设置分布式锁 demo
    内容来自对chatgpt的咨询分布式锁是在多个节点上运行的应用程序中协调工作的一种常用方法,而Redis是实现分布式锁的流行选择。以下是使用Go语言和github.com/go-redis/redis库来设置Redis分布式锁的一个简单示例:首先,确保你已经安装了该库:goget-ugithub.com/go-redis/redi......
  • Redis搭建集群架构
    使用docker搭建6.x版本以后的镜像docker支持部署集群模式,由于Redis要求集群至少要有三个主节点,因此本次测试搭建了三主三从的Redis集群。不基于Host网络模式配置docker-compose.yml文件version:"3"networks:redis-cluster:driver:bridgeipam:......
  • SpringBoot项目优化和JVM调优
    在开发中项目调优是必须得熟练掌握的事情。在SpringBoot项目中,调优主要通过配置文件和配置JVM的参数的方式进行。修改配置文件关于修改配置文件application.properties,可参考SpringBoot详细配置文件其中比较重要的有:#Maximumnumberofconnectionsthattheserveraccepts......
  • Redis 命令工具
    ---Redis命令工具---redis-serverRedis服务器启动命令redis-clishutdown停止服务redis-benchmark:性能测试工具,用于检测Redis在本机的运行效率redis-check-aof:修复有问题的AOF持久化文件redis-check-rdb:修复有问题的RDB持久化文件redis-cli:Redis客户端命令行......
  • 深入探讨Spring Boot中的Redis缓存
    介绍Redis是一种高性能的内存数据库,常用于缓存和消息队列等场景。在SpringBoot中,我们可以通过集成Redis来实现缓存功能。本文将深入探讨SpringBoot中的Redis缓存。集成Redis在SpringBoot中,我们可以通过添加以下依赖来集成Redis:<dependency><groupId>org.springframewor......