Redis

Redis学习(一)-- 基础

redis安装(linux)

参考官网教程

$ wget http://download.redis.io/releases/redis-6.0.6.tar.gz
$ tar zxvf redis-6.0.6.tar.gz
$ mv redis-6.0.6 /usr/local
$ cd /usr/local
$ mv redis-6.0.6 redis
$ cd redis
$ make

make 可能会报错原因为安装gcc执行如下命令

$ yum install gcc -y
$ yum install gcc-c++ -y
$ yum -y install centos-release-scl
$ yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
$ scl enable devtoolset-9 bash
#注意:scl命令启用只是临时的,推出xshell或者重启就会恢复到原来的gcc版本。
#如果要长期生效的话,执行如下:
$ echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
$ make distclean
$ make
$ make install

redis启动方式(linux)

  1. 直接启动redis
$ cd /src
$ ./redis-server
# ctrl+c 可以关闭
  1. 以后台进程方式启动redis
#修改配置文件
#将redis-conf拷贝到自定义文件夹
$ cp redis-conf /root/myredis
$ vim redis.conf
#修改daemonize no 为 daemonize yes
#vim下查询字符串 按:进入命令模式 /所查字符串+回车
#按i 进入输入模式,修改配置文件 按esc退出按:输入wq!保存退出、
#完成后启动使用自己的配置文件
$ redis-server /root/myredis/redis-conf
#进入redis
$ redis-cli
#如果有多个端口
$ redis-cli -p xxxx
#进入之后shutdown可以关闭redis服务,也可以不进入直接执行以下指令
$ redis-cli shutdown
$ redis-cli -p xxxx shutdown

基础知识

#redis基础命令
#使用第n个数据库,默认16个库即n:0~15
select n 
#查看当前库大小
DBSIZE
127.0.0.1:6379[3]> dbsize
(integer) 0
#插入数据
127.0.0.1:6379[3]> set num 100
OK
#查询数据
127.0.0.1:6379[3]> get num
"100"
#获取所有key
127.0.0.1:6379[3]> keys *
1) "num"
#清除数据
flushdb 清除当前数据库
flushall 清除所有数据库
#判断key是否存在
exists key
#设置过期时间(秒)
expire name 10 设置key为name 10秒过期
#查看过期时间
ttl name
#数据移动到目标库
move num 2 将num移动到数据库2

redis是单线程的,管方表示redis是基于内存操作的,CPU不是redis的瓶颈,redis的瓶颈是根据计算机的内存和网络带宽

为什么单线程还这么快?

redis将所有的数据存在内存中,所以单线程操作效率是最高的,多线程会有上下文切换,对于内存系统没有上下文切换效率就是最高的,多次读写都在一个cpu上,在内存情况下就是最佳方案。

Redis学习(二)-- 数据类型

#官网介绍
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.

#翻译
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

redis-key

#获取所有key
127.0.0.1:6379[3]> keys *
1) "num"
#清除数据
flushdb #清除当前数据库
flushall #清除所有数据库
#判断key是否存在
exists key
#设置过期时间(秒)(单点登录)
expire name 10 #设置key为name 10秒过期
#查看过期时间
ttl name
#数据移动到目标库
move num 2 #将num移动到数据库2
#查看当前key数据类型
type key


#官网查命令

redis数据类型–String类型

#追加字符串 类似java string方法
append key "hello" #如果key不存在,就相当于set
127.0.0.1:6379[2]> APPEND name ju
(integer) 6
127.0.0.1:6379[2]> get name
"julyju"
#获取字符串长度
strlen key
127.0.0.1:6379[2]> STRLEN age
(integer) 4
#i++操作 (可用于记录文章浏览量)
127.0.0.1:6379[2]> set views 0
OK
127.0.0.1:6379[2]> INCR views
(integer) 1
127.0.0.1:6379[2]> get views
"1"
#i--操作
127.0.0.1:6379[2]> INCR views
(integer) 2
127.0.0.1:6379[2]> DECR views
(integer) 1
127.0.0.1:6379[2]> get views
"1"
#i+=n、i-=n操作
INCRBY views 10
DECRBY views 10

#截取字符串
127.0.0.1:6379[2]> set name zxcvbbn
OK
127.0.0.1:6379[2]> get name
"zxcvbbn"
127.0.0.1:6379[2]> GETRANGE name 0 2 #截取字符串包含首尾
"zxc"
127.0.0.1:6379[2]> GETRANGE name 0 -1 #end为-1 截取开始到末尾
"zxcvbbn"

#替换
127.0.0.1:6379[2]> get name
"zxcvbbn"
127.0.0.1:6379[2]> SETRANGE name 2 qwq #替换从2开始的字符串
(integer) 7
127.0.0.1:6379[2]> get name
"zxqwqbn"

# setex (set with expire) 设置过期时间
# setnx (set if not exist) 不存在就设置(分布式锁)
127.0.0.1:6379[2]> SETEX my 30 hello # 设置30秒后过期
OK
127.0.0.1:6379[2]> ttl
(error) ERR wrong number of arguments for 'ttl' command
127.0.0.1:6379[2]> ttl my
(integer) 22
127.0.0.1:6379[2]> SETNX my2 12312hh #如果my2不存在则创建
(integer) 1
127.0.0.1:6379[2]> SETNX my2 ewr #如果my2存在则创建失败
(integer) 0
127.0.0.1:6379[2]> keys *
1) "my2"
2) "name"
127.0.0.1:6379[2]> ttl my
(integer) -2

#批量set
127.0.0.1:6379[2]> MSET k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379[2]> keys *
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379[2]> MSETNX k1 v1 k4 v4 #msetnx 是一个原子性操作,一起成功/失败
(integer) 0
127.0.0.1:6379[2]> keys *
1) "k3"
2) "k2"
3) "k1"

#批量获取
127.0.0.1:6379[2]> MGET k1 k2 k3
1) "v1"
2) "v2"
3) "v3"

#对象 
set user:1 {name:zhangsan,age:3} #设置一个user:1对象值为json字符串来保存对象

# key可以这么设计: user:{id}:{filed}
127.0.0.1:6379[2]> mset user:1:name zhangsan user:1:age 23 user:1:sex male
OK
127.0.0.1:6379[2]> MGET user:1:name user:1:age user:1:sex
1) "zhangsan"
2) "23"
3) "male"

#先get再set getset key value
127.0.0.1:6379[2]> getset mo mo # 如果不存在则返回null并创建
(nil)
127.0.0.1:6379[2]> get mo
"mo"
127.0.0.1:6379[2]> getset mo momo # 如果存在返回现在的值 并更新值
"mo"
127.0.0.1:6379[2]> get mo
"momo"

string类似的使用场景:value除了字符串还可以是数字

  • 计数器
  • 统计多单位的数量
  • 粉丝数
  • 对象缓存存储

redis数据类型–List类型

在redis 中可以将list用成栈、队列、阻塞队列

LPUSH
RPUSH
LRANGE
127.0.0.1:6379> LPUSH list 1 #将一个或多个值插入到队列表头部(左)
(integer) 1
127.0.0.1:6379> LPUSH list 2
(integer) 2
127.0.0.1:6379> LPUSH list 3
(integer) 3
127.0.0.1:6379> keys *
1) "list"
127.0.0.1:6379> LRANGE list 0 -1 #获取list的值 
1) "3"
2) "2"
3) "1"
127.0.0.1:6379> RPUSH list one tow #将一个或多个值插入到队列表尾部(右)
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "3"
2) "2"
3) "1"
4) "one"
5) "tow"

LPOP
RPOP
127.0.0.1:6379> LPOP list # 移出list头部第一个元素(左)
"3"
127.0.0.1:6379> LRANGE list 0 -1
1) "2"
2) "1"
3) "one"
4) "tow"
127.0.0.1:6379> RPOP list # 移出list尾部第一个元素(右)
"tow"
127.0.0.1:6379> LRANGE list 0 -1
1) "2"
2) "1"
3) "one"

LINDEX
127.0.0.1:6379> LINDEX list 0 # 通过下标获取list中的一个值
"2"

LLEN
127.0.0.1:6379> LLEN list # 获取list元素
(integer) 3

LREM #删除list中指定个数的value  精确匹配
127.0.0.1:6379> LRANGE list 0 -1 # list可以存放重复元素
1) "4"
2) "3"
3) "2"
4) "1"
5) "2"
6) "1"
7) "one"
127.0.0.1:6379> LREM list 1 2 #删除一个指定元素2
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "4"
2) "3"
3) "1"
4) "2"
5) "1"
6) "one"
127.0.0.1:6379> lrem list 2 1 #删除两个指定元素1
(integer) 2
127.0.0.1:6379> LRANGE list 0 -1
1) "4"
2) "3"
3) "2"
4) "one"

LTRIM 修剪
127.0.0.1:6379> LPUSH list 0 1 2 3 4 5
(integer) 6
127.0.0.1:6379> LRANGE list 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "0"
127.0.0.1:6379> LTRIM list 0 3 # 通过下标截取list指定区间的值,
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "5"
2) "4"
3) "3"
4) "2"

RPOPLPUSH # 移出列表的最后一个元素添加到新的列表
127.0.0.1:6379> RPOPLPUSH list list1
"2"
127.0.0.1:6379> LRANGE list 0 -1
1) "5"
2) "4"
3) "3"
127.0.0.1:6379> LRANGE list1 0 -1 #新列表不存在则新建
1) "2"

LSET
127.0.0.1:6379> EXISTS list
(integer) 1
127.0.0.1:6379> LSET list 1 err # 更新目标list指定下标的值
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "5"
2) "err"
3) "3"
127.0.0.1:6379> LSET list 5 ee # 目标key存在但是下标不存在 lset报错
(error) ERR index out of range
127.0.0.1:6379> LSET lis 3 ee # 目标key不存在lset报错
(error) ERR no such key

LINSERT
127.0.0.1:6379> LRANGE list 0 -1
1) "1"
2) "2"
3) "4"
127.0.0.1:6379> LINSERT list before 1 0 #在目标元素1前面插入0
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "0"
2) "1"
3) "2"
4) "4"
127.0.0.1:6379> LINSERT list after 2 3 #在目标元素2后面插入3
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
  • list 实际上是一个双向链表
  • 如果key不存在创建新的链表,如果key存在新增内容
  • 如果移出了所有值,空链表,代表不存在
  • 两边插入删除修改效率最高,中间值操作效率低

消息排队! 消息队列(左进右出)

redis数据类型–set类型

set中的值无序且不能重复

127.0.0.1:6379> sadd set hello world zyzy cs # 像set中插入元素
(integer) 4
127.0.0.1:6379> SMEMBERS set # 获取set中所有的元素
1) "world"
2) "cs"
3) "zyzy"
4) "hello"
127.0.0.1:6379> SISMEMBER set hello # 获取set中指定元素 存在返回1 否则返回0
(integer) 1							
127.0.0.1:6379> SISMEMBER set hello1
(integer) 0
127.0.0.1:6379> SCARD set # 获取set集合中数据的数量
(integer) 4
127.0.0.1:6379> SRANDMEMBER set 2 # 随机抽取指定数量的元素(不指定数量随机抽取一个)
1) "zyzy"
2) "cs"
127.0.0.1:6379> SREM set hello # 删除指定元素
127.0.0.1:6379> SPOP set # 随机移出1个元素
"hello"
127.0.0.1:6379> SMEMBERS set
1) "world"
2) "cs"
3) "zyzy"
127.0.0.1:6379> SMOVE set set2 cs #将指定元素移动到目标集合
(integer) 1
127.0.0.1:6379> SMEMBERS set2
1) "cs"
127.0.0.1:6379> SMEMBERS set
1) "world"
2) "zyzy"

 # 差集  并集  交集
 127.0.0.1:6379> SMEMBERS set
1) "world"
2) "zyzy"
3) "hello"
127.0.0.1:6379> SMEMBERS set2
1) "world"
2) "cs"
3) "hello"
127.0.0.1:6379> SDIFF set set2 # 差集 
1) "zyzy"
127.0.0.1:6379> SINTER set set2 # 交集
1) "world"
2) "hello"
127.0.0.1:6379> SUNION set set2 # 并集
1) "world"
2) "cs"
3) "zyzy"
4) "hello"

共同关注,共同好友等

redis数据类型–hash类型

Map集合,key-value(map集合)

127.0.0.1:6379> HSET hash k1 v1 k2 v2 # 添加hash
(integer) 2
127.0.0.1:6379> HGETALL hash # 获取所有元素
1) "k1"
2) "v1"
3) "k2"
4) "v2"
127.0.0.1:6379> HGET hash k1 # 获取指定元素
"v1"
127.0.0.1:6379> HDEL hash k1 # 删除指定元素
(integer) 1
127.0.0.1:6379> HGETALL hash
1) "k2"
2) "v2"
127.0.0.1:6379> HLEN hash # 获取hash表的长度
(integer) 1
127.0.0.1:6379> HEXISTS hash k1 #判断hash中指定字段是否存在
(integer) 0
127.0.0.1:6379> HEXISTS hash k2
(integer) 1
127.0.0.1:6379> hset hash k4 4
(integer) 1
127.0.0.1:6379> HINCRBY hash k4 1 #i++
(integer) 5
127.0.0.1:6379> HGET hash k4
"5"
127.0.0.1:6379> HSETNX hash k4 23 # 存在就不添加
(integer) 0
127.0.0.1:6379> HSETNX hash k5 23 # 不存在就新建
(integer) 1

hash变更数据,用户信息的存储,经常变动的值,hash适合存储对象,string适合存字符串

redis数据类型–zset类型(有序集合)

127.0.0.1:6379> ZADD key 1222 v1  12122 v2 121233 v3 # 插入zset 
(integer) 3
127.0.0.1:6379> ZREVRANGEBYSCORE key +inf -inf # 按score 从高到低排序
1) "v3"
2) "v2"
3) "v1"

有序的set 存储工资表、(加权)权重信息、排行榜

Redis学习(三)-- 三种特殊数据类型

geospatial地理位置,底层是zset实现的

朋友的定位,附近的人,打车距离计算

redis在3.2版本推出geo,可以推算地理位置信息

首先通过读配置将经纬度数据读到redis中

  • GEOADD:GEOADD key longgitude(经度) latitube(维度) member [longitude latitude member …]
127.0.0.1:6379> GEOADD china:city 116.397128 39.916527 beijing 121.48941 31.40527 shanghai
(integer) 2
  • GEODIST:GEODIST key member1 member2 [m|km|ft|mi]
127.0.0.1:6379> GEODIST china:city beijing shanghai #获取两地之间的直线距离 默认单位/米
"1052105.5643"
127.0.0.1:6379> GEODIST china:city beijing shanghai km
"1052.1056"
127.0.0.1:6379> GEODIST china:city beijing shanghai m
"1052105.5643"
127.0.0.1:6379> GEODIST china:city beijing shanghai ft
"3451789.9093"
127.0.0.1:6379> GEODIST china:city beijing shanghai mi
"653.7497"
  • GEOHASH: GEOHASH key member [member…]
#该命令将返回11个字符的Geohash字符串
127.0.0.1:6379> GEOHASH china:city beijing shanghai
1) "wx4g0dtf9e0"
2) "wtw6st1uuq0"
  • GEOPOS:GEOPOS key member [member …]
127.0.0.1:6379> GEOPOS china:city beijing shanghai #获取指定位置的经纬度
1) 1) "116.39712899923324585"
   2) "39.91652647362980844"
2) 1) "121.48941010236740112"
   2) "31.40526993848380499"
  • GEORADIUS:GEORADIUS key longitude latitude redius m|km|ft|mi [withcoord] [withdist] [withhash] [count count]
127.0.0.1:6379> GEORADIUS china:city 110 30 10000 km WITHCOORD WITHDIST WITHHASH COUNT 2 #以给定坐标为中心找出指定半径内的元素
1) 1) "shanghai"
   2) "1109.3250"
   3) (integer) 4054807796443227
   4) 1) "121.48941010236740112"
      2) "31.40526993848380499"
2) 1) "beijing"
   2) "1246.7595"
   3) (integer) 4069885548668386
   4) 1) "116.39712899923324585"
      2) "39.91652647362980844"
 
 #应用:附近的人
  • GEORADIUSBYMEMBER:GEORADIUSBYMEMBER key member redius m|km|ft|mi [withcoord] [withdist] [withhash] [count count] [ASC|DESC]
#找出以指定元素为中心的指定半径内的所有元素 包括自身
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 100000 km 
1) "shanghai"
2) "beijing"

*BitMaps 位存储

统计用户信息,活跃,不活跃,登录,未登录,两个状态都可以用bitmaps!

Bitmap位图,数据结构,操作二进制位来记录,只有0和1两个状态

记录一周的打卡情况

127.0.0.1:6379> SETBIT sign 0 0 
(integer) 0
127.0.0.1:6379> SETBIT sign 1 1
(integer) 0
127.0.0.1:6379> SETBIT sign 2 1
(integer) 0
127.0.0.1:6379> SETBIT sign 3 1
(integer) 0
127.0.0.1:6379> SETBIT sign 4 1
(integer) 0
127.0.0.1:6379> SETBIT sign 5 0
(integer) 0
127.0.0.1:6379> SETBIT sign 6 0
(integer) 0
127.0.0.1:6379> GETBIT sign 0
(integer) 0
127.0.0.1:6379> GETBIT sign 2
(integer) 1
127.0.0.1:6379> BITCOUNT sign # 统计打卡次数
(integer) 4

hyperloglog

什么是基数

A{1,3,5,7,8,7}基数是一个数据集不重复的数 = 5

**网页的UV(独立访客)**一个用户多次访问算一个

传统方法用set集合存储id,存储大量id

127.0.0.1:6379> PFADD se1t 1 2 3 4 5 6 7 8 9 0 1 
(integer) 1
127.0.0.1:6379> PFCOUNT se1t # 获取基数 不重复元素数
(integer) 10
127.0.0.1:6379> PFADD se2t 1 2 3 4 5 6 7 8 9 0 11 12 13 14 
(integer) 1
127.0.0.1:6379> PFMERGE set3t se1t se2t
OK
127.0.0.1:6379> PFCOUNT se3t
(integer) 0
127.0.0.1:6379> PFCOUNT set3t 
(integer) 14

Redis学习(四)-- redis事务

事务:ACID (要么同时成功要么同时失败,原子性)

redis单条命令是保证原子性的,但是事务是不保证原子性的

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

一次性,顺序性,排他性! 执行一系列的命令

redis事务没有隔离级别的概念!

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

redis的事务

  • 开启事务(multi)
  • 命令入列(…)
  • 执行事务(exec)

正常执行事务!

127.0.0.1:6379[2]> MULTI  # 开启事务
OK
# 命令入列
127.0.0.1:6379[2]> set num 12
QUEUED
127.0.0.1:6379[2]> set num2 13
QUEUED
127.0.0.1:6379[2]> set num3 14
QUEUED
127.0.0.1:6379[2]> get num3
QUEUED
127.0.0.1:6379[2]> STRLEN num
QUEUED
127.0.0.1:6379[2]> exec # 执行事务
1) OK
2) OK
3) OK
4) "14"
5) (integer) 2

放弃事务

127.0.0.1:6379[2]> MULTI
OK
127.0.0.1:6379[2]> set num 1
QUEUED
127.0.0.1:6379[2]> set num5 54
QUEUED
127.0.0.1:6379[2]> DISCARD # 取消事务
OK
127.0.0.1:6379[2]> get num5 # 队列中的事务都不被执行
(nil)

编译型异常(代码有问题!命令有错!),事务中的所有命令都不会被执行!

127.0.0.1:6379[2]> MULTI
OK
127.0.0.1:6379[2]> set k1 v1
QUEUED
127.0.0.1:6379[2]> set k2 v2
QUEUED
127.0.0.1:6379[2]> GETSET k2 # 错误命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379[2]> set k3 v3
QUEUED
127.0.0.1:6379[2]> exec #执行事务报错  所有命令都不执行
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379[2]> get k1
(nil)
127.0.0.1:6379[2]> get k3
(nil)

运行时异常(比如:1/0),如果事务队列中存在语法性错误,那么错误命令抛异常,其他命令正常执行!

127.0.0.1:6379[2]> MULTI  # 开启事务
OK
127.0.0.1:6379[2]> set k1 v1
QUEUED
127.0.0.1:6379[2]> INCR k1 #错误命令 只能incr integer类型的数据
QUEUED
127.0.0.1:6379[2]> get k1
QUEUED
127.0.0.1:6379[2]> exec # 错误命令抛异常,其他命令正常运行
1) OK
2) (error) ERR value is not an integer or out of range 
3) "v1"

##Redis学习(五)-- redis监控(watch)

悲观锁

  • 很悲观,认为随时会出问题,无论什么操作都加锁

乐观锁

  • 很乐观,认为无论何时都不会吃问题,不会上锁,更新数据的时候去判断版本
  • mysql中获取version,更新数据时比较version
127.0.0.1:6379[2]> WATCH money out # 加锁
OK
127.0.0.1:6379[2]> MULTI
OK
127.0.0.1:6379[2]> INCRBY out 10
QUEUED
127.0.0.1:6379[2]> DECRBY money 10
QUEUED
127.0.0.1:6379[2]> exec # 执行事务前开启另一个客户端修改money的值,事务执行失败
(nil)

# 如果执行失败,先解锁,再获取最新值重新操作
127.0.0.1:6379[2]> UNWATCH # 解锁
OK
127.0.0.1:6379[2]> WATCH money out # 获取最新值,再次监视
OK
127.0.0.1:6379[2]> MULTI
OK
127.0.0.1:6379[2]> DECRBY money 10
QUEUED
127.0.0.1:6379[2]> INCRBY out 10
QUEUED
127.0.0.1:6379[2]> EXEC #比较监视的值在监视过程中有没有发生变化,若变化执行失败,若不变执行成功
1) (integer) 990
2) (integer) 30
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值