Redis事务机制详解与Springboot项目中的使用

JAVA SpringBoot中使用redis的事务 1、自定义redisConfig , 如果项目中要使用redis事务,最好将用事务和不用事务的redis分开。 阅读详情

Redis 的事务机制允许将多个命令打包在一起,作为一个原子操作来执行。虽然 Redis 的事务与关系型数据库的事务有所不同,但它仍然提供了一种确保多个命令顺序执行的方式。以下是 Redis 事务机制的详细解析:


1. Redis 事务的基本概念

Redis 事务通过以下四个命令实现:

  • MULTI:开启一个事务。
  • EXEC:执行事务中的所有命令。
  • DISCARD:取消事务,放弃所有已入队的命令。
  • WATCH:监视一个或多个键,如果在事务执行前这些键被修改,则事务不会执行。

Redis 事务的核心思想是将多个命令放入一个队列中,然后一次性、按顺序执行这些命令。


2. Redis 事务的工作流程

2.1 开启事务

使用 MULTI 命令开启一个事务。开启事务后,所有后续的命令都会被放入一个队列中,而不是立即执行。

127.0.0.1:6379> MULTI
OK
2.2 命令入队

在事务开启后,所有命令都会被放入队列中,等待执行。例如:

127.0.0.1:6379> SET key1 value1
QUEUED
127.0.0.1:6379> SET key2 value2
QUEUED
2.3 执行事务

使用 EXEC 命令执行事务中的所有命令。Redis 会按顺序执行队列中的命令,并返回每个命令的执行结果。

127.0.0.1:6379> EXEC
1) OK
2) OK
2.4 取消事务

如果在事务执行前需要取消事务,可以使用 DISCARD 命令。这会清空事务队列并退出事务。

127.0.0.1:6379> DISCARD
OK

3. Redis 事务的特性

3.1 原子性

Redis 事务是原子的,这意味着事务中的所有命令要么全部执行,要么全部不执行。但是,Redis 事务不支持回滚(rollback)。如果在事务执行过程中某个命令失败,后续命令仍然会继续执行。

3.2 隔离性

Redis 事务是隔离的,事务中的命令在 EXEC 执行之前不会被其他客户端看到。其他客户端只有在事务提交后(即 EXEC 执行后)才能看到事务的结果。

3.3 无回滚机制

Redis 事务不支持回滚。如果在事务执行过程中某个命令失败(例如语法错误),Redis 不会自动回滚已经执行的命令。这与关系型数据库的事务机制不同。

3.4 命令入队

在事务开启后,所有命令都会被放入队列中,而不是立即执行。只有在 EXEC 命令被调用时,队列中的命令才会被执行。


4. WATCH 命令

WATCH 命令用于监视一个或多个键。如果在事务执行前这些键被其他客户端修改,则事务不会执行。WATCH 提供了一种乐观锁机制,用于解决并发问题。

4.1 使用 WATCH
127.0.0.1:6379> WATCH key1
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key1 value1
QUEUED
127.0.0.1:6379> EXEC
(nil)  # 如果 key1 被其他客户端修改,事务不会执行
4.2 取消 WATCH

使用 UNWATCH 命令可以取消对所有键的监视。

127.0.0.1:6379> UNWATCH
OK

5. Redis 事务的局限性

5.1 不支持回滚

Redis 事务不支持回滚。如果在事务执行过程中某个命令失败,Redis 不会自动回滚已经执行的命令。

5.2 命令错误与运行时错误
  • 命令错误:如果事务中的某个命令存在语法错误(例如命令不存在),则整个事务都不会执行。
  • 运行时错误:如果事务中的某个命令在执行时出错(例如对字符串执行 INCR 操作),则只有该命令会失败,其他命令仍然会执行。
5.3 性能问题

Redis 事务会将所有命令放入队列中,直到 EXEC 执行时才一次性执行。如果事务中包含大量命令,可能会导致内存占用过高。


6. Redis 事务的应用场景

6.1 批量操作

当需要一次性执行多个命令时,可以使用事务来确保这些命令按顺序执行。

6.2 乐观锁

通过 WATCH 命令可以实现乐观锁机制,确保在事务执行前监视的键没有被修改。

6.3 原子性操作

虽然 Redis 事务不支持回滚,但它仍然可以确保多个命令的原子性执行。


7. Redis 事务与 Lua 脚本的对比

Redis 事务和 Lua 脚本都可以用于实现原子性操作,但两者有以下区别:

  • 事务:适合简单的批量操作,但不支持复杂的逻辑。
  • Lua 脚本:适合复杂的业务逻辑,支持条件判断、循环等操作,且脚本在服务器端原子执行。

8. Redis 事务的示例

以下是一个完整的 Redis 事务示例:

# 监视 key1
127.0.0.1:6379> WATCH key1
OK

# 开启事务
127.0.0.1:6379> MULTI
OK

# 命令入队
127.0.0.1:6379> SET key1 value1
QUEUED
127.0.0.1:6379> SET key2 value2
QUEUED

# 提交事务
127.0.0.1:6379> EXEC
1) OK
2) OK

在 Spring Boot 中使用 Redis 事务机制时,可以通过 RedisTemplate 或 StringRedisTemplate 来操作 Redis 事务。Spring Data Redis 提供了对 Redis 事务的支持,允许你在 Spring 应用中方便地使用 Redis 事务。

9. 在 Spring Boot 中使用 Redis 事务

9.1 配置 RedisTemplate

首先,确保在 Spring Boot 项目中配置了 RedisTemplate 或 StringRedisTemplate。

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}
9.2 使用 Redis 事务

在 Spring Boot 中,可以通过 RedisTemplate 的 execute 方法来执行事务操作。execute 方法接受一个 SessionCallback 或 RedisCallback 参数,用于在事务中执行多个命令。

@Service
public class RedisTransactionService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public void executeTransaction() {
        redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                // 开启事务
                operations.multi();

                // 执行多个命令
                operations.opsForValue().set("key1", "value1");
                operations.opsForValue().set("key2", "value2");

                // 提交事务
                return operations.exec();
            }
        });
    }
}
9.3 使用 WATCH 命令

WATCH 命令用于监视一个或多个键,如果在事务执行前这些键被修改,则事务不会执行。可以通过 RedisTemplate 的 watch 方法来实现。

@Service
public class RedisTransactionService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public void executeTransactionWithWatch() {
        redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                // 监视 key1
                operations.watch("key1");

                // 开启事务
                operations.multi();

                // 执行多个命令
                operations.opsForValue().set("key1", "value1");
                operations.opsForValue().set("key2", "value2");

                // 提交事务
                return operations.exec();
            }
        });
    }
}
9.4. 事务的异常处理

在 Redis 事务中,如果某个命令执行失败,事务不会回滚,而是继续执行后续命令。因此,需要在代码中处理可能的异常情况。

@Service
public class RedisTransactionService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public void executeTransactionWithExceptionHandling() {
        redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                try {
                    // 开启事务
                    operations.multi();

                    // 执行多个命令
                    operations.opsForValue().set("key1", "value1");
                    operations.opsForValue().set("key2", "value2");

                    // 提交事务
                    return operations.exec();
                } catch (Exception e) {
                    // 处理异常
                    operations.discard();
                    throw e;
                }
            }
        });
    }
}
9.5. 使用注解驱动的事务管理

Spring Data Redis 支持通过 @Transactional 注解来管理 Redis 事务。需要在配置类中启用事务管理。

@Configuration
@EnableTransactionManagement
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setEnableTransactionSupport(true); // 启用事务支持
        return template;
    }

    @Bean
    public PlatformTransactionManager transactionManager(RedisConnectionFactory redisConnectionFactory) {
        return new DataSourceTransactionManager();
    }
}

然后在 Service 类中使用 @Transactional 注解来标记事务方法。

@Service
public class RedisTransactionService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Transactional
    public void executeTransactionWithAnnotation() {
        redisTemplate.opsForValue().set("key1", "value1");
        redisTemplate.opsForValue().set("key2", "value2");
    }
}

总结

在 Spring Boot 中使用 Redis 事务机制时,可以通过 RedisTemplate 的 execute 方法手动管理事务,也可以通过 @Transactional 注解实现声明式事务管理。使用 WATCH 命令可以确保事务的原子性,避免竞态条件。在实际应用中,需要根据业务需求选择合适的事务管理方式,并注意异常处理和性能优化。

Redis 由浅入深 (8) - Springboot 中的Redis 事务使用 有一些场景我们可以在一段代码中多次操作redis,每次请求Redis都要去Jedis/Lettuce连接池申请一个连接请求一次redis服务进行缓存操作。 这样不仅有网络的消耗,假如在redis连接数吃紧的情况下多次请求redis很有可能回造成redis获取连接超时。懂得redis的兄弟这时候会说可以使用pipeline解决啊!确实我们使用pipeline批量命令去请求redis会解决上述问题,但还有一种场景就是我上一个redis请求成功了,但下一个请求失败了,这个时候上一个请求我需要回滚怎么办?..... 阅读详情

相关推荐

springboot-redis事务

springboot-redis事务

springboot使用redis事务

Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。标记一个事务块的开始。执行所有事务块的命令。

justlpf的专栏 1269

腾讯云服务器被攻击,带宽被占满的抗战日记

故事 时间:2021-08-23 地点:腾讯云服务器 事件:服务器内容被黑,修复后某人气不过,开始DDOS,占满服务器的带宽,导致网站访问非常缓慢。 杂记 根据腾讯云后台+宝塔后台,带宽被占满:(小垃圾水管没办法) 部分参考:记一次阿里云服务器ECS流出带宽占满的解决过程 https://blog.youkuaiyun.com/wangzhihao1994/article/details/99563456 首先是在云主机上使用远程连接访问到云主机,安装iftop工具 CentOS .

Rudon滨海渔村的博客 1303

SpringBoot中使用redis事务

redis事务只支持单机,不支持cluster需要开启事务时,只需要在对应的方法或类上使用注解即可,SpringBoot自动开启了@EnableTransactionManagement需要注意事务不生效的几种情况redis事务依赖于jdbc的事务管理。

justlpf的专栏 2057

IEC61850客户端连接实战:CMS vs MMS协议抓包对比与性能初探(基于YX-PIS协议栈)

本文深入探讨了IEC61850客户端连接中CMS与MMS协议的抓包对比与性能优化。通过Wireshark抓包分析、协议栈配置实战和性能基准测试,揭示了两种协议在连接建立、数据交互和性能调优方面的关键差异,为智能电网自动化系统的协议选择提供了实用指南。

weixin_29209805的博客 215

SimNow模拟环境实战:用vnpy_ctp连接期货市场的5个关键配置步骤

本文提供了一份详细的量化交易实战指南,重点讲解如何使用vnpy_ctp插件连接SimNow期货模拟环境的5个关键配置步骤。内容涵盖SimNow环境选择、vnpy_ctp核心参数解析、实战连接脚本编写、深度排错技巧以及向实盘迁移的准备,旨在帮助量化交易开发者快速搭建可靠的测试环境,避免常见陷阱。

weixin_29063035的博客 1272

Redis6笔记03 SpringBoot整合Redis,事务和锁机制,持久化操作

在pom.xml文件中引入redis相关依赖 修改springboot配置文件 创建配置类 测试成功!Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化,按顺序的执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。Redis事务的主要作用就是串联多个命令防止别的命令插队。输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令列表中的命令一次执行。组队过程中可以通过discard来放弃组队。组队阶段命令错误报告错

qq_53157982的博客 1269

AI赋能传染病建模:从数据到动力学模型的本地实践指南

这次我们来看一个将 AI 与传染病动力学建模结合的前沿方向。想象一下,你手头有一份流感爆发的病例数据,传统的建模方法可能需要复杂的微分方程和大量的手动调参,而 AI 模型能否直接从数据中“学习”出传播规律,甚至自动跑通整个建模流程?这正是当前研究的热点。根据《Nature》的最新综述,人工智能正在重塑传染病流行病学建模,从参数推断、趋势预测到多源数据融合,AI 技术为解决传统建模中的计算瓶颈和数据难题提供了全新路径。 对于开发者、数据科学家或公共卫生领域的研究者而言,最关心的是:这套方法能不能在本地跑起来?

weixin_29051811的博客 297

Spring、SpringBoot、Redis、Mysql 事务管理机制汇总

目录 一、Spring事务管理之几种方式实现事务  二、SpringBoot事务管理  三、Redis的事务功能详解 (一)相关命令 1. MULTI 2. EXEC 3. DISCARD 4. WATCH 5. UNWATCH (二)使用方法 (三)事务内部的错误 (四)为什么Redis不支持回滚? (五)丢弃命令队列 (六)通过CAS操作实现乐观锁 (七)WATC...

YuZongTao 4263

A2B音频总线在智能座舱中的应用

车载A2B链路音频是智能座舱的核心功能,涵盖车载音响、语音识别、e-Call、消噪及回声消除等应用,随着汽车智能网联化的发展,对音频的开发要求也越来越高,需要加入更先进、功能丰富的信息娱乐功能以满足消费者的用户体验。但传统的模拟并行音频信号传输方式,难以在功能增加与整车轻量化(线缆的重量及成本减少)之间取得均衡。这时候就需要A2B音频总线了。A2B音频总线用于连接车辆中的音频设备,如麦克风(MIC)、功放(AMP)、多媒体主机(Head Unit)和T-BOX等。通过一条低成本的非屏蔽双绞线UTP,进行跨距

怿星科技的博客 3934

15、分布式查询处理详解

本博文深入探讨了分布式环境下的查询处理与优化技术。从查询处理的基本概念出发,分析了在分布式系统中执行查询所面临的额外挑战,并通过实例比较了不同的执行策略。文章详细介绍了查询优化的组成要素,包括搜索空间、成本模型和搜索策略,同时涵盖了查询处理的多个层次以及数据本地化的核心方法。此外,还讨论了连接排序优化、分布式成本模型以及多种查询优化方法,如静态优化、动态优化和混合优化。最后,提出了自适应查询处理的概念,旨在提高分布式查询的灵活性和效率。通过综合应用这些技术,可以有效提升分布式数据库的查询性能,降低通信和计算

gan8painter的博客 73

16-SpringBoot之Redis(三)——Redis事务机制

SpringBoot之Redis(三)——Redis事务机制1. Redis 事务执行过程2. 开启事务支持3. 测试4. 测试结果说明5. 源码下载 1. Redis 事务执行过程 Redis 事务执行过程如下图所示: 2. 开启事务支持 RedisConfig.java文件EnbaleTransactionSupport设为true @Bean public RedisTemplat...

HJ的技术博客 2043

RK3399快速上手 | 01- 开发环境搭建(固件烧写、编译工具链安装、kernel编译)

一、编译工具链 编译工具链使用gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu。 下载地址: https://releases.linaro.org/components/toolchain/binaries/6.3-2017.05/arm-linux-gnueabihf/ wget https://releases.linaro.org/components/toolchain/binaries/6.3-2017.05/arm-linux-gnueabi

Mculover666的博客(嵌入式) 8835

Redis(简介和安装,常用数据类型和命令,Jedis客户端程序,SpringBoot整合Redis,配置文件解读,事务锁机制及案例,持久化,主从复制,集群操作)

NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库。NoSQL 不依赖业务逻辑方式存储,而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。不遵循SQL标准。不支持ACID。远超于SQL的性能。1 能够独立完成redis数据库的安装和启动方式调试2 能够简单操作redis数据库。

小丁的博客 1736

2026年广东省职业院校技能大赛中职组“大数据应用与服务”样题一完整参考答案

2026年广东省职业院校技能大赛中职组“大数据应用与服务”样题一完整参考答案

我是网络安全兼技能大赛工程师,专注网络安全技术学习与技能大赛实战!持续分享最新的技术文章,帮你少走弯路,一起在技术赛道上进步~ 739

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Redis使用详解(超详细运用实践 + springboot集成)

关系型数据库 MySQL 、oracleNoSQL数据库 非关系型数据库 分类键值存储 查找速度快 数据无结构化列存储数据库 查找速度快、可拓展性强,容易进行分布式扩展 功能相对局限文档型数据库 数据结构要求不严格,表结构可变,不需要预定义表结构 查询性能不高,缺乏统一的查询语法图形数据库 利用图结构相关算法,不好做分布式的集群方案。

m0_63600788的博客 1545

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Redis(发布订阅、事务、redis整合springboot、集成 Spring Cache)

可以一次执行多个命令,本质是一组命令的集合。一个事务中的 所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。单独的隔离的操作官网说明这四个指令构成了 redis 事务处理的基础。1.MULTI 用来组装一个事务;将命令存放到一个队列里面2.EXEC 用来执行一个事务;//commit3.DISCARD 用来取消一个事务;//rollback4.WATCH 用来监视一些 key,一旦这些 key 在事务执行之前被改变,则取消事务的执行。

weixin_47735032的博客 2518

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Redis - 事务及Springboot应用

Redis事务 Redis每一个命令都是原子性的 事务可以一次执行多个命令(顺序的串行执行) Redis会将一个事务中所有命令序列化,顺序执行,不会被其他命令插入,不许出现加塞现象 Redis没有在事务上增加任何维持原子性的机制,所以Redis事务的执行并不是原子性的 Redis事务不支持回滚 命令 multi标记开始一个事务块 exec执行事务块的命令 discard 取消事务,放弃执行事务块命令 watch key[key...]监视一个或多个key,在事务执行前该key被其他命令改

key_768的博客 518

redis基础知识随记

Redis笔记1 Redis概念2 Redis基本知识3 基本数据类型3.1 String3.1.1 数据结构3.1.2 基本命令3.2 List3.2.1 数据结构3.2.2 基本命令3.3 Set3.3.1 数据结构3.3.2 基本命令3.4 Hash3.4.1 数据结构3.4.2 基本命令3.5 Zset3.5.1 数据结构3.5.2 基本命令4 发布与订阅5 Redis测试案例6 Redis的事务和锁机制6.1 multi、exec、discard6.2 事务的错误处理6.3 悲观锁与乐观锁6.4

xuwenze的博客 1087

【redis系列】springboot使用redis事务

事务处理 redis事务提供了一种“将多个命令打包, 然后一次性、按顺序地执行”的机制, 并且事务在执行的期间不会主动中断 —— 服务器在执行完事务中的所有命令之后, 才会继续处理其他客户端的其他命令。 Redis中的事务是可以视为一个队列,即我们可以通过MULTI开始一个事务,这相当于我们声明了一个命令队列。 接下来,我们向Redis中提交的每条命令,都会被排入这个命令队列。 当我们输入EXEC命令时,将触发当前事务,这相当于我们从命令队列中取出命令并执行,所以Redis中一个事务从开始到执行会经历 开始

Think_and_work的博客 4411

【进阶篇】2.6 Redis 事务详解

Redis 事务是一种将多个命令打包在一起执行的机制,可以保证这些命令的原子性,即要么全部执行成功,要么全部执行失败。开启事务在客户端执行 MULTI 命令时,Redis 会将该客户端标记为事务状态。此时,客户端发送的所有命令都会被暂存到一个事务队列中,而不是立即执行。执行事务在客户端执行 EXEC 命令时,Redis 会将客户端状态从事务状态中移除,并依次执行事务队列中的所有命令。在执行期间,Redis 会将事务队列中的命令全部执行完毕,而不会中途中断。

日拱一卒无有尽,功不唐捐终入海 7万+

16、《SpringBoot+MyBatis集成(4) - 性能优化 - 事务与缓存机制剖析》

在企业级应用开发中,MyBatis作为持久层框架的标杆,与SpringBoot的集成已成为开发标配。本文将以**MyBatis-Plus为核心**,深度探讨声明式事务管理、多级缓存设计与批量操作优化三大核心命题,通过原理剖析、性能对比和实战演示,助力开发者构建高性能、高可靠性的数据访问层。

朗朗的博客 1489

SpringBoot整合Redis事务全解析

需要注意的是Redis事务操作并不像是关系型数据库那样具有原子性和隔离性,根据上面的介绍Redis事务操作其实是一组命令的集合,而这些命令是按它们在事务执行过程中的顺序来执行的,并且在事务执行过程中不会被其他的客户端打断。但是,如果其中一个命令执行失败,Redis不会回滚之前已经执行成功的命令,这需要开发者自己处理。这是什么意思呢?就是说在事务中的命令要么全部成功要么全部失败,但是如果对于mulit、exec这样的命令如果执行失败了,那么依旧是无法保证事务操作的。

2501_93873871的博客 877

Redis事务了解以及整合SpringBoot

文章目录Redis事务监控 WatchJedis Redis事务 事务Redis 事务本质: 一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程的中,会按照顺序执行!一次性、顺序性、排他性、执行一些列的命令! Redis事务没有没有隔离级别的概念! 所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会执行! Redis单条命令式保存原子性的,但是事务不保证原子性! redis的事务: 开启事务(multi) 命令入队(…) 执行事务(exec) 取消事务 (DISCARD)

weixin_44861399的博客 239

Redis数据库 | 事务、持久化

Redis数据库 | 事务、持久化

wei_shuo的博客 803
上一篇: java 把一个整型数组倒着输出来方式
下一篇: 【某大厂一面】ThreadLocal如何实现主子线程之间的数据同步
冰糖心书房
博客等级 码龄15年 6014粉丝 690原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值