Reids基本使用 5.08 版本

Reids 5.08 版本

1.概述

1.1 Redis是什么

Redis是一个开源的,内存中的数据结构存储系统,它可以作用**数据库**、**缓存**、**消息中间件**。它支持多种数据结构,如字符串(String)、散列(hashes)、集合(lists)、有序集合(sorted sets)与范围查询、butnaos、hyperloglogs和地理空间(geospatial)索引版经常哈寻,Redis内置了 复制(replication),LUA脚本(luascripting),LRU驱动事件(LRU eviction),事务(transactiobns)和不同级别的磁盘持久化(persistence),并通过Redis哨兵(Sentienl)和自动分区(Cluster)提供高可用性(high availability)

1.2 Reids能做什么

​ 1.内存存储,持久化。内存是断电就失去,所以说持久化很重化(rdb、aof)

​ 2.效率高,可以用于告诉缓存

​ 3.发布订阅系统

​ 4.吸毒信息分析

​ 5.计时器,计数器(如浏览量)

​ 6…

1.3 特性

1.多样化数据类型

2.集群

3.持久化

4.事务

2.安装

2.1 Windows下安装

​ 1.下载安装包:https://github.com/dmakic/redis/releases

​ 2.解压

​ 3.执行redis-server.exe启动服务

​ 4.使用reids-cli.exe客户端连接reids

​ 输入指令ping 如果返回个pong就代表连接成功

Reid文件介绍

redis-server.exe : redis启动服务

redis-cli.exe : redis客户端

redis-check-aof.exe : redis检查持久化文件是否正确

redis-benchmark.exe: redis测试性能

Redis推荐在Linux下使用

2.2 linux下的安装

参考Linux安装Redis的笔记

3.基本语法

Redis 命令手册: http://redis.cn/commands.html

查看是什么类型

type

查看剩余过期时间

ttl 键

设置数据过期时间 # 设置10秒后过期

expire name 10

从当前数据库移除此键

move 键 1

判断某个键是否存在,如果存在返回1 不存在返回0

exists 键

redis默认有16个数据库,在redis.conf中有个databases 16

默认使用的是第0个 ,可以使用select 切换数据库

select 2

查看当前数据库容量大小 当我们存入一个值 容量就+1

DBSIZE

查看数据库所有的key

keys *

清空当前库

flushdb

清空所有库

flushall

4.基础知识

4.1 Redis是单线程的

​ Redis是基于内存操作的,CPU不是Redis的性能瓶颈,Redis的瓶颈是根据机器的内存和网络的带宽,既然可以使用单线程实现就可以使用单线程了。

为什么单线程还这么快?

核心:redis是将所有的数据全部放在了内存中,所以使用单线程效率是最高的。

​ 多线程会产生CPU上下文切换,这是一个很耗时的操作,对于内存系统来说秒如果没有上下文切换效率就是最高的。多次读写都是在一个CPU上的,在内存的情况来看就是最佳方案。

5.常见五大数据类型

51 String(字符串类型)

设置值

set 键名 值

取值

get 键名

追加

append 键值 追加的内容

当我们追加成功会返回字符串的追加后的长度

如果我们的键不存在就会创建一个新的,就相当于set key

获取字符串长度

strlen 键

自增

127.0.0.1:6379> set num 0		# 设置num的值为0
OK
127.0.0.1:6379> get num			# 获取num的值
"0"
127.0.0.1:6379> incr num		# num自增1
(integer) 1
127.0.0.1:6379> get num			# 获取num的值.
"1"

自减

127.0.0.1:6379> set num 1		# 设置num为0
OK		
127.0.0.1:6379> get num			# 获取num的值
"1"	
127.0.0.1:6379> decr num		# 使得num自减1
(integer) 0
127.0.0.1:6379> get num			# 获取num的值
"0"

步长 自增

127.0.0.1:6379> set num 1		# 设置num值为1
OK
127.0.0.1:6379> incrby num 9	# 让num加9
(integer) 10
127.0.0.1:6379> get num			# 获取num的值
"10"

步长 自减

127.0.0.1:6379> set num 10		# 设置num值为10
OK
127.0.0.1:6379> DECRBY num 5	# 使num自减5
(integer) 5

获取范围字符串

127.0.0.1:6379> set str1 "hello world"	# 设置值
OK
127.0.0.1:6379> get str1				# 取值
"hello world"
127.0.0.1:6379> GETRANGE str1 0 4		# 获取0-4的范围字符串
"hello"
127.0.0.1:6379> GETRANGE str1 0 -1		# 获取全部的字符串
"hello world"

替换字符串

127.0.0.1:6379> set str2 abcdefg		# 设置值
OK
127.0.0.1:6379> get str2				# 获取值
"abcdefg"
127.0.0.1:6379> SETRANGE str2 1 xx		# 替换键值为str2的下标为1替换为xx,如果替换值的长度大于1,比如替换值长度为2那么就替换下标为1的位置数2位进行替换
(integer) 7
127.0.0.1:6379> get str2
"axxdefg"

创建键并且设置过期时间

127.0.0.1:6379> SETEX str4 300 "hello"		# 创建键设置过期时间为300秒
OK
127.0.0.1:6379> get str4					# 获取键
"hello"	
127.0.0.1:6379> ttl str4					# 查看过期时间
(integer) 276

创建减 如果该键不存在则创建 如果存在则创建失败

127.0.0.1:6379> setnx mykey "dazui"			# 创建键 并且判断该键是否存在 如果创建失败
(integer) 1
127.0.0.1:6379> get mykey
"dazui"
127.0.0.1:6379> setnx mykey "dazu666i"		# 创建键 该键已经存在创建失败
(integer) 0
127.0.0.1:6379> get mykey
"dazui"

一次性设置多个值 批量设置 | 获取多个值 批量获取多个值

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 k4 v4	# 设置多个值
OK
127.0.0.1:6379> keys *
1) "k4"
2) "k1"
3) "k2"
4) "k3"

####################################################################
127.0.0.1:6379> mget k1 k2 k3 k4 			   # 获取多个值
1) "v1"
2) "v2"
3) "v3"
4) "v4"
####################################################################
127.0.0.1:6379> mset k1 v2 k2 v3
OK
127.0.0.1:6379> msetnx k1 v3 k2 v4				# 如果设置的键存在就创建失败
(integer) 0

创建对象

127.0.0.1:6379> mset user:1:name "dazui" user:1:age 18		#创建user对象1 名字为dazui  年龄为18
OK
127.0.0.1:6379> mget user:1:name user:1:age					#获取user对象1 名字和  age信息
1) "dazui"
2) "18"
127.0.0.1:6379

getset 使用 可以用于更新

127.0.0.1:6379> getset name dazuizui		#设置name值 如果该值没值就获取null  如果有值就获取之前的值并且替换
(nil)
127.0.0.1:6379> get name
"dazuizui"
127.0.0.1:6379> getset name wasaidazuihaoshuai		#获取之前的值 并且将新值覆盖
"dazuizui"

5.2 list(列表)

list插入值 查询值

127.0.0.1:6379> rpush list 1		# 右插入一个数据
(integer) 1
127.0.0.1:6379> rpush list 2		# 右插入一个数据
(integer) 2
127.0.0.1:6379> lpush list 0		# 左插入一个数据
(integer) 3
127.0.0.1:6379> lrange list 0 -1	# 查询所有数据
1) "0"
2) "1"
3) "2"

移除值

127.0.0.1:6379> lpop list  			# 移除左侧第一个值
"0"
127.0.0.1:6379> rpop list 			# 移除右侧第一个值
"2"
127.0.0.1:6379> lrange list 0 -1	# 查询所有数据
1) "1"
127.0.0.1:6379> 

获取指定下标的数据

127.0.0.1:6379> lindex list 1		# 获取指定下标为1的数据
"2"	
127.0.0.1:6379> lindex list 0		# 获取指定下标为0的数据
"1"
127.0.0.1:6379> lindex list 5		# 获取指定下标为5的手机壳
(nil)

获取队列的长度

127.0.0.1:6379> llen list			# 获取长度
(integer) 3

移除指定的值

127.0.0.1:6379> lrange list 0 -1	# 获取值
1) "1"
2) "2"
3) "3"
4) "4"
5) "4"
6) "4"
7) "4"
127.0.0.1:6379> lrem list 1 "4"		# 移除一个元素并且值为4
(integer) 1
127.0.0.1:6379> lrem list 2 "4"		# 移除凉饿元素并且值为4
(integer) 2

保留指定下标区间的数据

127.0.0.1:6379> lrange list 0 -1	# 获取所有数据
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> ltrim list 1 2		# 只保留指定下标区间的数据 其他数据都被截取
OK
127.0.0.1:6379> lrange list 0 -1	# 获取所有数据
1) "2"
2) "3"

移动列表最后一个元素,将他移动到其他列表中

127.0.0.1:6379> lrange list 0 -1		# 获取list表所有数据
1) "2"
2) "3"
127.0.0.1:6379> rpoplpush list list1	# 将list列表右侧第一个数据移至到新的列表中
"3"
127.0.0.1:6379> lrange list1 0 -1		# 查询list1列表所有数据 
1) "3"

指定下标添加值

127.0.0.1:6379> lpush list 0		# 左插入一个数据
(integer) 1
127.0.0.1:6379> exists list			# 判断键是否存在
(integer) 1
127.0.0.1:6379> exists list1		# 判断键是否存在
(integer) 0
127.0.0.1:6379> lset list 0 dazui	# 向list集合下标为0的地方插入值,如果下标0的位置已有值就会被替换
OK									# 插入成功
127.0.0.1:6379> lset list1 0 dazui	# 向list1集合下标为0的地方插入值
(error) ERR no such key				# 插入失败,因为list1键值不存在
127.0.0.1:6379> lrange list 0 -1	# 查询数
1) "dazui"

在指定值得前方或者后方插入一个值

127.0.0.1:6379> lrange list 0 -1								# 查询所有制
1) "dazui"
127.0.0.1:6379> LINSERT list before "dazui" "hello"				# 在dazui字符串前方插入一个字符
(integer) 2
127.0.0.1:6379> lrange list 0 -1								# 查询所有字符
1) "hello"
2) "dazui"
127.0.0.1:6379> linsert list after "dazui" "haoshuai"			# 在dazui字符串后方插入一个字符
(integer) 3
127.0.0.1:6379> lrange list 0 -1								# 查看所有字符
1) "hello"
2) "dazui"
3) "haoshuai"

5.3 set集合

​ set的值不可以重复,也是无序的

添加元素

127.0.0.1:6379> sadd sei "hello"  # 添加值
(integer) 1
127.0.0.1:6379> sadd sei "dazui"  # 添加值
(integer) 1

查询所有值

127.0.0.1:6379> smembers sei
1) "dazui"
2) "hello"

查看元素是否存在

127.0.0.1:6379> sismember sei hello		# 查看元素是否存在,如果存在返回1
(integer) 1
127.0.0.1:6379> sismember sei hello1	# 查看元素知否存在,如果存在返回0
(integer) 0

查看集合个数

127.0.0.1:6379> scard sei				# 查询是否存在
(integer) 2

删除指定元素

127.0.0.1:6379> srem sei hello			# 移除指定元素
(integer) 1

随机获取元素

127.0.0.1:6379> smembers sei			# 查询所有元素
1) "hello"
2) "dazui"
127.0.0.1:6379> SRANDMEMBER sei			# 随机获取一个元素
"dazui"

随机删除指定的key

127.0.0.1:6379> spop sei				# 随机删除一个值
"dazui"
127.0.0.1:6379> 

将一个值引用到另一个集合

127.0.0.1:6379> smove sei myset "dazui"# 将sei里的dazui元素移至到myset元素
(integer) 1
127.0.0.1:6379> SMEMBERS myset			# 查询myset集合
1) "dazui"
127.0.0.1:6379> smembers sei			# 查询sei集合
1) "hello"
127.0.0.1:6379> 

查询两个集合之间的差集

127.0.0.1:6379> smembers sei 			# 查询sei集合
1) "dazui"
2) "hello"
127.0.0.1:6379> smembers myset			# 查询myset集合
1) "dazui"
127.0.0.1:6379> sdiff sei myset			# 查询他们的差集
1) "hello"

查询两个集合的交集

127.0.0.1:6379> sinter myset sei		# 查询交集
1) "dazui

查询两个集合的合集

127.0.0.1:6379> SUNION sei myset		# 查询合集
1) "hello"
2) "dazui"
127.0.0.1:6379> 

5.4 Hash (哈希)

添加 获取

127.0.0.1:6379> hset hash1 k1 12		# hash名叫hash1 键值叫k1 值为12
(integer) 1
127.0.0.1:6379> hset hash1 k2 13 k3 14  # 设置多个值
(integer) 2
127.0.0.1:6379> hget hash1 k1			# 获取指定值
"12"
127.0.0.1:6379> hmget hash1 k2 k3		# 获取多个指定值
1) "13"
2) "14"

删除指定值 获取全部之

127.0.0.1:6379> hdel hash1 k1			# 删除指定值
(integer) 1
127.0.0.1:6379> hgetall hash1			# 获取全部键值对
1) "k2"
2) "13"
3) "k3"
4) "14"

获取hash表的长度

127.0.0.1:6379> hlen hash1				# 获取长度
(integer) 2

获取指定键是否存在

127.0.0.1:6379> HEXISTS hash1 k2		# 判断指定键是否存在
(integer) 1

获取所有的键 获取所有的值

127.0.0.1:6379> hkeys hash1				# 查看所有键
1) "k2"
2) "k3"
127.0.0.1:6379> HVALS hash1				# 查看所有值
1) "13"
2) "14"

自增自减

 127.0.0.1:6379> hincrby hash1 k2 2
(integer) 15
127.0.0.1:6379> hincrby hash1 k3 -2
(integer) 12
127.0.0.1:6379> hvals hash1
1) "15"
2) "12"

5.5 Zset(有序集合)

127.0.0.1:6379> zadd key1 1 one				# 将下标为1的地方添加数据
(integer) 1
127.0.0.1:6379> zadd key1 2 two				# 将下标为2的地方添加数据
(integer) 1
127.0.0.1:6379> zadd key1 2  three			# 将下标为2的地方添加数据 如果下标为2的地方有数据 下标为2的数据向后移动,将新数据放在下标为2的最前方, 当前下标为2的数据有three two
(integer) 1
127.0.0.1:6379> zrange key 0 -1
(empty array)
127.0.0.1:6379> zrange key1 0 -1
1) "one"
2) "three"
3) "two"
127.0.0.1:6379> 

查询所有数据并且带序号

127.0.0.1:6379> zrangebyscore key1 -inf +inf withscores			# 查询所有数据并且带序号
1) "one"
2) "1"
3) "three"
4) "2"
5) "two"
6) "2"

查看小于某个序号的值

127.0.0.1:6379> zrangebyscore key1 -inf 2 withscores			# 查询小于2的所值,并且打印序号	
1) "one"
2) "1"
3) "three"
4) "2"
5) "two"
6) "2"
127.0.0.1:6379> zrangebyscore key1 -inf +inf					# 查询小于2的的数据
1) "one"
2) "three"
3) "two"

移除指定元素元素

127.0.0.1:6379> zrem key1 two									# 移除指定元素two
(integer) 1	

查看多少个元素

127.0.0.1:6379> zcard key1										# 获取有序集合的格式
(integer) 3

查看从大到小序号的值

127.0.0.1:6379> zrevrange key1 0 -1 withscores					# 查询从大到小的序号的值
1) "two"
2) "5"
3) "five"
4) "5"
5) "three"
6) "2"
7) "one"
8) "1"

查看区间的值有几个

127.0.0.1:6379> zrange key1 0 -1 withscores						# 查看所有值并且显示序号
1) "one"
2) "1"
3) "three"
4) "2"
5) "two"
6) "2"
7) "five"
8) "5"
127.0.0.1:6379> zcount key1 0 3									# 查询0-3区间的值有几个
(integer) 3

6.三种特殊数据类型

6.1 geospatial (地理位置)

geospatial可以存放城市维度

有效精度 -180度到 180度

有效维度-85.05112878度到85.05112878度

**维度查询网站:**http://www.jsons.cn/lngcode/

添加地理位置

127.0.0.1:6379> geoadd HongKong:city 115.164167 22.2664163 hongkong				# 插入HongKong的维度
(integer) 1
127.0.0.1:6379> geoadd HongKong:city 114.17495 22.327115 jiulong				# 插入HongKong JiuLong的维度
(integer) 1

获取指定城市坐标

127.0.0.1:6379> geopos HongKong:city jiulong									# 获取HongKong JiuLong的经度纬度
1) 1) "114.17495101690292358"
   2) "22.3271154118881654"

两个位置的距离

127.0.0.1:6379> geodist HongKong:city hongkong jiulong km						# 查看两者之间的距离
"102.0236"

m标识单位为米

km表示单位为千米

mi标识单位为英里

ft标识单位为英尺

附近的人

​ 以给定的经纬度为中心,找出某一半径内的元素

127.0.0.1:6379> georadius HongKong:city 115.164167 22.2664163 100 km
1) "jlc"
2) "hongkong"
127.0.0.1:6379> georadius HongKong:city 115.164167 22.2664163 1000 km
1) "jiulong"
2) "jlc"
3) "hongkong"

以位置为中心附近的位置

127.0.0.1:6379> georadiusbymember HongKong:city hongkong 100 km					# 查看hongkong周围100km的城市
1) "jlc"
2) "hongkong"

6.2Hyperloglog(基数统计)

做什么?

​ 如果允许容错,可以使用Hyperloglog进行计数

什么是基数

​ A{1,3,5,7,8,9} B{1,3,5,7}

​ 就是查找不重复的元素

基本使用

127.0.0.1:6379> pfadd key3 a b b3 d f g h i j k									# 添加数据
(integer) 1
127.0.0.1:6379> pfcount key3													# 查询数据返回长度
(integer) 10
127.0.0.1:6379> pfadd key2 i j k z x c v b n									# 添加数据
(integer) 1
127.0.0.1:6379> pfmerge key key2 key3											# 合并key3 key2的数据返回给key
OK
127.0.0.1:6379> pfcount key 													# 查询key长度,Hyperloglog重复的数据会添加失败
(integer) 15
127.0.0.1:6379> pfadd key3 qw													# 添加数据
(integer) 1
127.0.0.1:6379> pfcount key3													# 查询数据返回长度
(integer) 11

6.3 Bitmaps(位图)

​ 他的值只有0和1

​ 就来做个签到系统为案例

设置值 --0为未签到1为签到

127.0.0.1:6379> setbit bhk 0 1
(integer) 0
127.0.0.1:6379> setbit bhk 2 1
(integer) 0
127.0.0.1:6379> setbit bhk 3 0
(integer) 0
127.0.0.1:6379> setbit bhk 1 0
(integer) 0
127.0.0.1:6379> setbit bhk 4 0
(integer) 0
127.0.0.1:6379> setbit bhk 5 1
(integer) 0
127.0.0.1:6379> setbit bhk 6 1
(integer) 0

查看值 --如果返回0为未签到如果返回1为签到

127.0.0.1:6379> getbit bhk 4
(integer) 0
127.0.0.1:6379> getbit bhk 6
(integer) 1

查看为1的数据

127.0.0.1:6379> bitcount bhk 
(integer) 4

7.基本的事务操作

7.1事务

​ Redis事务的本质:一组命令的集合,一块执行!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行。

​ **特性:**一次性、顺序性、排他性!

Redis事务没有隔离级别的概念

所有的命令在事务中,没有直接被执行,只有发起执行命令的时候才会执行。

Redis单条命令保存原子性,事务不保证原子性。

7.2 Redis的事务

1.开启事务(multi)

127.0.0.1:6379> multi 								# 开启事务
OK

2.命令入队 (写命令)

# 命令入队
127.0.0.1:6379> set name dazui 
QUEUED
127.0.0.1:6379> set age 18
QUEUED

3.执行事务 (exec)

127.0.0.1:6379> exec								# 执行
1) OK

正常执行事务!

127.0.0.1:6379> multi 								# 开启事务
OK
127.0.0.1:6379> set name dazui						# 命令入队
QUEUED
127.0.0.1:6379> exec								# 执行事务
1) OK

放弃事务

127.0.0.1:6379> multi								# 开启事务
OK
127.0.0.1:6379> set k1 a							# 命令入列
QUEUED
127.0.0.1:6379> set k2 a							# 命令入列
QUEUED
127.0.0.1:6379> DISCARD								# 放弃事务
OK
127.0.0.1:6379> get k1								# 获取String数据
(nil)

编译型异常

代码有问题或者命令有错误

​ 如果触发了事务中所有命令都不会执行

127.0.0.1:6379> multi								# 创建事务
OK
127.0.0.1:6379> set a1 a
QUEUED
127.0.0.1:6379> set a2 a
QUEUED
127.0.0.1:6379> set a3 a
QUEUED
127.0.0.1:6379> getset a1							# 错误命令入列
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set a4 4
QUEUED
127.0.0.1:6379> exec								# 执行事务,报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get a1								# 证明了所有的命令都没有被执行
(nil)

运行时异常

​ 比如1/0报错,如果事务队列中存在余发星,那么执行命令的时候其他命令都是可以正常执行的,错误命令抛出异常

127.0.0.1:6379> multi								# 创建事务
OK
127.0.0.1:6379> set k1 "v1"							# 设置值 加入命令队列
QUEUED
127.0.0.1:6379> incr k1								# 对k1进行自加1,但是k1存放的的数据不是纯数字,就会报错	加入队列
QUEUED
127.0.0.1:6379> set k2 12							# 设置值 加入队列
QUEUED
127.0.0.1:6379> exec								# 执行事务
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
127.0.0.1:6379> get k2								# 获取k2数据 证明运行时异常其他命令可以正常执行。
"12"

8.加锁

8.1 悲观锁

​ 悲观锁认为什么时候都会出问题,无论做什么都会加锁。这样做特别影响性能。

8.2 乐观锁

​ 他认为什么时候都不会出现问题。更新数据的时候去判断下,在此期间是否有人修改过这个数据。

8.3 监视

正常执行

127.0.0.1:6379> set money 100									# 设置100块钱
OK
127.0.0.1:6379> set out 0										# 设置花出去的钱
OK
127.0.0.1:6379> watch money										# 监视
OK
127.0.0.1:6379> MULTI											# 创建事务
OK
127.0.0.1:6379> decrby money 20									# 钱自减20
QUEUED	
127.0.0.1:6379> incrby out 20									# 花出去的钱自增20
QUEUED
127.0.0.1:6379> exec											# 执行
1) (integer) 80
2) (integer) 20

并发情况

线程A

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money										# 监视
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby money 20
QUEUED
127.0.0.1:6379> exec											# 执行 一定要在线程B执行完再去执行 为什么失败?因为在在执行事务他会比较money跟监视时候的值是否相同,如果相同就可以执行,不相同就执行失败,这时候线程B修改了money的值,所以更新失败
(nil)

线程B

127.0.0.1:6379> set money 10000
OK

放弃监视 解锁

127.0.0.1:6379> UNWATCH											# 取消加锁
OK

9.番外

1.为什么Reids是6379

Alessia Merz 是一位意大利舞女、女演员。 Redis 作者 Antirez 早年看电视节目,觉得 Merz 在节目中的一些话愚蠢可笑,Antirez 喜欢造“梗”用于平时和朋友们交流,于是造了一个词 “MERZ”,形容愚蠢,与 “stupid” 含义相同。

后来 Antirez 重新定义了 “MERZ” ,形容”具有很高的技术价值,包含技艺、耐心和劳动,但仍然保持简单本质“。

到了给 Redis 选择一个数字作为默认端口号时,Antirez 没有多想,把 “MERZ” 在手机键盘上对应的数字 6379 拿来用了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

哇塞大嘴好帅(DaZuiZui)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值