Redis学习笔记

1.什么是Redis

Redis 是一个开源的使用C语言编写,支持网络,可基于内存可持久化的日志型、高性能的Key-Value数据库,并支持多语言的API调用。它通常被成为数据结构服务器,因为Value值可以是多种数据类型(字符串(String)、集合(set)、列表(list)、哈希(Map)、有序集合(sorted set))等类型。

Redis的特点:

  • Redis支持数据持久化存储,可以将内存保存的数据持久化的存放到磁盘中,重启的时候可以在次的加载使用。
  • Redis不仅仅支持Key-Value类型的数据,还支持 字符串(String)、集合(set)、列表(list)、哈希(Map)、有序集合(sorted set)等多种数据类型。
  • Redis支持主从模式,即master-slave模式的主从模型。

Redis的优点:

  • 性能极高 (Redis能读的速度是110000次/s,写的速度是81000次/s)。
  • 支持丰富的数据类型 (Redis支持二进制案例的字符串(String)、集合(set)、列表(list)、哈希(Map)、有序集合(sorted set)等多种数据类型)。
  • 可用于缓存、消息、按key设置过期时间,过期自动删除。
  • 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行。
  • 支持分布式读写分离模式。

2.安装Redis(Linux)

2.1 下载Redis:

下载Redis安装包(下载地址:http://download.redis.io/releases/)

wget http://download.redis.io/releases/redis-4.0.8.tar.gz

2.2 安装Redis:

解压、编译(编译的时候需要gcc的依赖 在安装之前一定保证gcc是安装好的,可以使用yum -y install gcc 安装)

[root@BrianZhu ~]# tar zxf redis-4.0.8.tar.gz 
[root@BrianZhu ~]# cd redis-4.0.8/
[root@BrianZhu redis-4.0.8]# make

2.3 启动Redis:

二进制文件是编译完成后在src目录下,通过下面的命令启动Redis服务:

[root@BrianZhu redis-4.0.8]# src/redis-server

看到下面的图片表示启动成功:

 这里的启动方式,是让Redis在前台启动,我们不退出Redis终端就会一直这样显示,当我们关掉终端Redis的进程也就退出了,为了解决这个问题 我们要把Redis放到后台启动,使用下面的方法:

[root@BrianZhu redis-4.0.8]# nohup src/redis-server &

检查Redis启动状态:

[root@BrianZhu redis-4.0.8]# netstat -lntup | grep redis
tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      47592/src/redis-ser 
tcp6       0      0 :::6379                 :::*                    LISTEN      47592/src/redis-ser 

注:redis-server默认启动的端口是6379端口,默认没有密码

在启动的时候Redis调用的是配置文件redis.conf文件(文件路径在解压后redis目录下面)

[root@BrianZhu redis-4.0.8]# pwd
/root/redis-4.0.8
[root@BrianZhu redis-4.0.8]# ll | grep redis.conf
-rw-rw-r--  1 root root  58353 Feb  3 00:39 redis.conf

如果我们自定义的这个文件的路径,也可以指定这个文件的路径进行启动:

[root@BrianZhu redis-4.0.8]# nohup src/redis-server ~/redis-4.0.8/redis.conf &

2.4 启动Redis客户端并且验证:

我们可以使用内置的客户端命令redis-cli进行使用:

[root@BrianZhu redis-4.0.8]# src/redis-cli 
127.0.0.1:6379>                     # 已经启动Redis客户端

验证(一个简单的使用):

[root@BrianZhu redis-4.0.8]# src/redis-cli 
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set var "Hello World"
OK
127.0.0.1:6379> get var
"Hello World"
127.0.0.1:6379> 

退出客户端终端:

[root@BrianZhu redis-4.0.8]# src/redis-cli 
127.0.0.1:6379> quit
[root@BrianZhu redis-4.0.8]# src/redis-cli 
127.0.0.1:6379> exit

2.5 停止Redis:

我们可以使用内置的语法命令 redis-cli shutdown 来关闭Redis:

[root@BrianZhu redis-4.0.8]# src/redis-cli shutdown

具体操作如下:

[root@BrianZhu redis-4.0.8]# netstat -lntup | grep redis
tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      47592/src/redis-ser 
tcp6       0      0 :::6379                 :::*                    LISTEN      47592/src/redis-ser 
[root@BrianZhu redis-4.0.8]# src/redis-cli shutdown
[1]+  Done                    nohup src/redis-server
[root@BrianZhu redis-4.0.8]# netstat -lntup | grep redis
[root@BrianZhu redis-4.0.8]# 

注:如果是设置上密码后,单纯的使用redis-cli是关不掉的,必须加上IP、Port、Passwd

[root@BrianZhu redis-4.0.8]# src/redis-cli -h 192.168.31.1 -p 6379 -a 123456 shutdown

3.设置密码,远程连接

3.1设置Redis密码:

redis没有实现访问控制这个功能,但是它提供了一个轻量级的认证方式,可以编辑redis.conf配置来启用认证。

有两种设置密码的方式:

  • 修改配置文件,需要重启redis:在配置文件中有个参数: requirepass  这个就是配置redis访问密码的参数(500行左右);比如 requirepass test123 ;  注:( redis的查询速度是非常快的,外部用户一秒内可以尝试多大150K个密码;所以密码要尽量长(对于DBA 没有必要必须记住密码)

  

  • 使用内置的语法命令设置密码,不重启Redis设置密码:
[root@BrianZhu redis-4.0.8]# src/redis-cli 
设置密码
127.0.0.1:6379> config set requirepass test123
OK
查询密码:
redis 127.0.0.1:6379> config get requirepass
(error) ERR operation not permitted

密码验证:
redis 127.0.0.1:6379> auth test123
OK
再次查询:
redis 127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "test123"

注:如果配置文件中没添加密码 那么redis重启后,密码失效;

3.2 远程连接Redis:

远程连接也是有两种方式:

  • 登录的时候加上密码验证:
[root@BrianZhu redis-4.0.8]# src/redis-cli -p 6379 -a test123
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) "test123"
127.0.0.1:6379> 
  •  登录以后在使用auth进行验证
[root@BrianZhu redis-4.0.8]# src/redis-cli 
127.0.0.1:6379> CONFIG GET requirepass
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth test123
OK
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) "test123"
127.0.0.1:6379> 

注:AUTH命令跟其他redis命令一样,是没有加密的;阻止不了攻击者在网络上窃取你的密码;认证层的目标是提供多一层的保护。如果防火墙或者用来保护redis的系统防御外部攻击失败的话,外部用户如果没有通过密码认证还是无法访问redis的。

4.Redis的数据类型

Redis支持五种数据类型:

  • 字符串(String)
  • 集合(set)
  • 列表(list)
  • 哈希(Map)
  • 有序集合(sorted set)

4.1 字符串(String):

  • 是Redis最基本的数据类型,可以理解成与Memcached一样的类型,一个Key对应一个Value。
  • 二进制安全的。意思就是Redis的String可以包含任何数据,因为他是以二进制的方式存储的。
  • 一个键最大存储512MB。

常用字符串命令具体操作如下:

127.0.0.1:6379> set name "Brian Zhu"
OK
SET key value (给key赋值)
127.0.0.1:6379> get name
"Brian Zhu"
GET key (获取指定 key 的值)
127.0.0.1:6379> GETRANGE name 0 6
"Brian Z"
127.0.0.1:6379> GETRANGE name 0 -1
"Brian Zhu"
GETRANGE key start end (返回 key 中字符串值的子字符)
127.0.0.1:6379> GETSET name "Brian"
"Brian Zhu"
GETSET key value (将给定 key 的值设为 value ,并返回 key 的旧值(old value))
127.0.0.1:6379> GETBIT name 1
(integer) 1
127.0.0.1:6379> GETBIT name 3
(integer) 0
127.0.0.1:6379> GETBIT oo 1    # oo这个key不存在
(integer) 0
 
# 当偏移量 OFFSET 比字符串值的长度大,或者 key 不存在时,返回 0
GETBIT key offset (对 key 所储存的字符串值,获取指定偏移量上的位(bit))
127.0.0.1:6379> MGET name
1) "Brian"
127.0.0.1:6379> mget name keys 
1) "Brian"
2) "hello world"
127.0.0.1:6379> mget name keys oo
1) "Brian"
2) "hello world"
3) (nil)

# 没有的变量返回nil
MGET key1 [key2..] (获取所有(一个或多个)给定 key 的值)
127.0.0.1:6379> SETBIT name 10086 1
(integer) 0
127.0.0.1:6379> GETBIT name 10086
(integer) 1
127.0.0.1:6379> GETBIT name 100   # 默认被初始为0
(integer) 0
SETBIT key offset value(对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit))
127.0.0.1:6379> SETEX test 60 brian
OK
127.0.0.1:6379> TTL test
(integer) 54
127.0.0.1:6379> GET test
"brian"
127.0.0.1:6379> TTL test
(integer) -2
127.0.0.1:6379> GET test
(nil)

#  设置时间过期,key对应的value也将过期
SETEX key seconds value (将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位))
127.0.0.1:6379> EXISTS job     # 查看job是否存在
(integer) 0 
127.0.0.1:6379> SETNX job "hahaha"   # 设置job
(integer) 1  
127.0.0.1:6379> SETNX job "nidaye"    # 覆盖job失败
(integer) 0
127.0.0.1:6379> GET job                   # 查看job值还是原来的值
"hahaha"
SETNX key value (只有在 key 不存在时设置 key 的值)
127.0.0.1:6379> GET job
"hahaha"
127.0.0.1:6379> SETRANGE job 2 "nidaye"  
(integer) 8
127.0.0.1:6379> GET job
"hanidaye"
SETRANGE key offset value(用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始)
127.0.0.1:6379> GET job
"hanidaye"
127.0.0.1:6379> STRLEN job
(integer) 8
STRLEN key(返回 key 所储存的字符串值的长度)
127.0.0.1:6379> mset key1 brian key2 18
OK
127.0.0.1:6379> get key1
"brian"
127.0.0.1:6379> get key2
"18"
MSET key value [key value ...](同时设置一个或多个 key-value 对)
127.0.0.1:6379> MSETNX key1 brian key2 19    # key1 和key2存在创建失败
(integer) 0
127.0.0.1:6379> MSETNX key3 jack key4 19
(integer) 1
127.0.0.1:6379> GET key3
"jack"
127.0.0.1:6379> GET key4
"19"
MSETNX key value [key value ...] (同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在)
127.0.0.1:6379> PSETEX test1 10000 "100000000"
OK
127.0.0.1:6379> PTTL test1
(integer) 8092
127.0.0.1:6379> GET test1
"100000000"
127.0.0.1:6379> PTTL test1
(integer) -2
127.0.0.1:6379> GET test1
(nil)
PSETEX key milliseconds value(这个命令和SETEX命令相似,但它以毫秒为单位设置 key的生存时间,而不是像 SETEX 命令那样,以秒为单位)
127.0.0.1:6379> SET number 100
OK
127.0.0.1:6379> INCR number
(integer) 101
127.0.0.1:6379> get number
"101"
INCR key(将 key 中储存的数字值增一)
127.0.0.1:6379> GET number
"101"
127.0.0.1:6379> INCRBY number 100
(integer) 201
127.0.0.1:6379> GET number
"201"
INCRBY key increment(将 key 所储存的值加上给定的增量值(increment)
127.0.0.1:6379> GET number
"201"
127.0.0.1:6379> INCRBYFLOAT number 100.9999
"301.99990000000000001"
127.0.0.1:6379> GET number
"301.99990000000000001"
INCRBYFLOAT key increment(将 key 所储存的值加上给定的浮点增量值(increment)
127.0.0.1:6379> GET number
"100"
127.0.0.1:6379> DECR number
(integer) 99
127.0.0.1:6379> GET number
"99"
DECR key(将 key 中储存的数字值减一)
127.0.0.1:6379> GET number
"99"
127.0.0.1:6379> DECRBY number 10
(integer) 89
127.0.0.1:6379> GET number
"89"
DECRBY key decrement(key 所储存的值减去给定的减量值(decrement)
127.0.0.1:6379> GET job
"hanidaye"
127.0.0.1:6379> APPEND job "niyade"
(integer) 14
127.0.0.1:6379> GET job
"hanidayeniyade"
127.0.0.1:6379> APPEND ll poip
(integer) 4
127.0.0.1:6379> GET ll
"poip"
APPEND key value(如果key已经存在并且是一个字符串,APPEND命令将指定value追加到改key原来的值(value)的末尾,key不存在则添加key)

4.2 集合(Set):

  • Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
  • Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
  • 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

常用集合命令具体操作如下:

127.0.0.1:6379> SADD myset "hello"
(integer) 1
127.0.0.1:6379> SADD myset "foo"
(integer) 1
127.0.0.1:6379>  SADD myset "hello"
(integer) 0
127.0.0.1:6379> SMEMBERS myset
1) "foo"
2) "hello"
SADD key member1 [member2] (向集合添加一个或多个成员)
127.0.0.1:6379> SCARD myset
(integer) 2
SCARD key (获取集合的成员数)
127.0.0.1:6379> SMEMBERS myset
1) "foo"
2) "hello"
127.0.0.1:6379> SMEMBERS brian
1) "foo"
2) "fo"
3) "nihao"
127.0.0.1:6379> SDIFF myset brian
1) "hello"
SDIFF key1 [key2] (返回给定所有集合的差集)
127.0.0.1:6379> SMEMBERS myset
1) "foo"
2) "hello"
127.0.0.1:6379> SMEMBERS brian
1) "foo"
2) "fo"
3) "nihao"
127.0.0.1:6379> SINTER myset brian
1) "foo"
SINTER key1 [key2] (返回给定所有集合的交集)
127.0.0.1:6379> SDIFFSTORE myset2 brian myset
(integer) 2
127.0.0.1:6379> SMEMBERS myset2
1) "fo"
2) "nihao"
SDIFFSTORE destination key1 [key2] (返回给定所有集合的差集并存储在 destination 中)
127.0.0.1:6379> SINTERSTORE myset3 brian myset
(integer) 1
127.0.0.1:6379> SMEMBERS myset3
1) "foo"
SINTERSTORE destination key1 [key2] (返回给定所有集合的交集并存储在 destination 中)
127.0.0.1:6379> SISMEMBER brian fo   # 存在
(integer) 1
127.0.0.1:6379> SISMEMBER brian do  # 不存在
(integer) 0
SISMEMBER key member (判断 member 元素是否是集合 key 的成员)
127.0.0.1:6379> SMEMBERS myset3
1) "foo"
127.0.0.1:6379> SMEMBERS myset
1) "foo"
2) "hello"
SMEMBERS key (返回集合中的所有成员)
127.0.0.1:6379> SMOVE myset foo foo
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "hello"
127.0.0.1:6379> SMEMBERS foo
1) "foo"
SMOVE source destination member (将 member 元素从 source 集合移动到 destination 集合)
127.0.0.1:6379> SMEMBERS brian
1) "foo"
2) "fo"
3) "nihao"
127.0.0.1:6379> SPOP brian
"nihao"
127.0.0.1:6379> SMEMBERS brian
1) "foo"
2) "fo"
SPOP key (移除并返回集合中的一个随机元素)
127.0.0.1:6379> SRANDMEMBER brian
"foo"
127.0.0.1:6379> SRANDMEMBER brian
"foo"
127.0.0.1:6379> SRANDMEMBER brian
"fo"
SRANDMEMBER key [count] (返回集合中一个或多个随机数)
127.0.0.1:6379> SMEMBERS brian
1) "fo"
2) "wwwwwww"
3) "a"
4) "hhahaha"
5) "foo"
6) "d"
7) "b"
8) "c"
127.0.0.1:6379> 
127.0.0.1:6379> SREM brian wwwwwww d
(integer) 2
127.0.0.1:6379> SMEMBERS brian
1) "fo"
2) "a"
3) "hhahaha"
4) "foo"
5) "b"
6) "c"
SREM key member1 [member2] (移除集合中一个或多个成员)
127.0.0.1:6379> SMEMBERS myset
1) "foo"
2) "a"
3) "c"
4) "hello"
127.0.0.1:6379> SMEMBERS brian
1) "fo"
2) "a"
3) "hhahaha"
4) "foo"
5) "b"
6) "c"
127.0.0.1:6379> SUNION brian myset
1) "fo"
2) "a"
3) "hello"
4) "hhahaha"
5) "foo"
6) "b"
7) "c"
SUNION key1 [key2] (返回所有给定集合的并集)
127.0.0.1:6379> SUNIONSTORE mysets brian myset
(integer) 7
127.0.0.1:6379> SMEMBERS mysets
1) "fo"
2) "a"
3) "hello"
4) "hhahaha"
5) "foo"
6) "b"
7) "c"
SUNIONSTORE destination key1 [key2] (所有给定集合的并集存储在 destination 集合中)

4.3 列表(List):

  • Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
  • 一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)

常用列表命令具体操作如下:

127.0.0.1:6379> LPUSH mylist "hello"
(integer) 1
127.0.0.1:6379> LPUSH mylist "hello" "world"
(integer) 3
LPUSH key value1 [value2] (将一个或多个值插入到列表头部)
127.0.0.1:6379> LRANGE mylist 0 -1
1) "world"
2) "hello"
3) "hello"
127.0.0.1:6379> LRANGE mylist 0 3
1) "world"
2) "hello"
3) "hello"
127.0.0.1:6379> LRANGE mylist 0 4
1) "world"
2) "hello"
3) "hello"
127.0.0.1:6379> LRANGE mylist 0 1
1) "world"
2) "hello"
LRANGE key start stop (获取列表指定范围内的元素)
127.0.0.1:6379> LPUSHX mylist nihao
(integer) 4
127.0.0.1:6379> LRANGE mylist 0 -1
1) "nihao"
2) "world"
3) "hello"
4) "hello"
LPUSHX key value (将一个值插入到已存在的列表头部)
127.0.0.1:6379> LREM mylist -2 hello
(integer) 2
127.0.0.1:6379> LRANGE mylist 0 -1
1) "nihao"
2) "world"
LREM key count value (移除列表元素)
127.0.0.1:6379> LRANGE mylist 0 -1
1) "nihao"
2) "world"
127.0.0.1:6379> LSET mylist 1 hahaha
OK
127.0.0.1:6379> LRANGE mylist 0 -1
1) "nihao"
2) "hahaha"
LSET key index value (通过索引设置列表元素的值)
127.0.0.1:6379> RPOP mylist
"hahaha"
RPOP key (移除并获取列表最后一个元素)
127.0.0.1:6379> RPOPLPUSH mylist mylist2
"dd"
127.0.0.1:6379> LRANGE mylist 0 -1
1) "nihao"
2) "aa"
3) "bb"
4) "cc"
127.0.0.1:6379> LRANGE mylist2 0 -1
1) "dd"
RPOPLPUSH source destination (移除列表的最后一个元素,并将该元素添加到另一个列表并返回)
127.0.0.1:6379> RPUSH mylist "aa" "bb" "cc" "dd"
(integer) 5
127.0.0.1:6379> LRANGE mylist 0 -1
1) "nihao"
2) "aa"
3) "bb"
4) "cc"
5) "dd"
RPUSH key value1 [value2] (在列表中添加一个或多个值)
127.0.0.1:6379> RPUSHX mylist2 "nihaoya"
(integer) 2
127.0.0.1:6379> LRANGE mylist2 0 -1
1) "dd"
2) "nihaoya"
RPUSHX key value (为已存在的列表添加值)
127.0.0.1:6379> LRANGE mylist 0 -1
1) "nihao"
2) "aa"
3) "bb"
4) "cc"
127.0.0.1:6379> LPOP mylist
"nihao"
127.0.0.1:6379> LRANGE mylist 0 -1
1) "aa"
2) "bb"
3) "cc"
LPOP key (移出并获取列表的第一个元素)
127.0.0.1:6379> LRANGE mylist 0 -1
1) "aa"
2) "bb"
3) "cc"
127.0.0.1:6379> LLEN mylist
(integer) 3
LLEN key (获取列表长度)
127.0.0.1:6379> LRANGE mylist 0 -1
1) "aa"
2) "bb"
3) "cc"
127.0.0.1:6379> LINDEX mylist 2
"cc"
LINDEX key index (通过索引获取列表中的元素) 

4.4 哈希(Map):

  • 是一个键值对的集合
  • 是一个String类型的field和value的映射表,hash特别适合用于存储对象
  • Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)

常用哈希命令具体操作如下:

127.0.0.1:6379> HSET test2 name jack
(integer) 1
HSET key field value(将哈希表 key 中的字段 field 的值设为 value)
127.0.0.1:6379> HGET test2 name
"jack"
HGET key field (获取存储在哈希表中指定字段的值)
127.0.0.1:6379> HMSET names one brian two jack
OK
HMSET key field1 value1 [field2 value2 ] (同时将多个 field-value (域-值)对设置到哈希表 key 中)
127.0.0.1:6379> HMGET names one two
1) "brian"
2) "jack"
HMGET key field1 [field2] (获取所有给定字段的值)
127.0.0.1:6379> HDEL names two
(integer) 1
127.0.0.1:6379> HGET name two
(error) WRONGTYPE Operation against a key holding the wrong kind of value
HDEL key field1 [field2] (删除一个或多个哈希表字段)
127.0.0.1:6379> HEXISTS names two    # 不存在
(integer) 0  
127.0.0.1:6379> HEXISTS names one    # 存在
(integer) 1
HEXISTS key field (查看哈希表 key 中,指定的字段是否存在)
127.0.0.1:6379> HGETALL names
1) "one"                  # 哈希表key
2) "brian"                # key对应的值
HGETALL key (获取在哈希表中指定 key 的所有字段和值)
127.0.0.1:6379> HSET ages one 100
(integer) 1
127.0.0.1:6379> HINCRBY ages one 10
(integer) 110
127.0.0.1:6379> HGET ages one
"110"
HINCRBY key field increment (为哈希表 key 中的指定字段的整数值加上增量 increment)
127.0.0.1:6379> HGET ages one
"110"
127.0.0.1:6379> HINCRBYFLOAT ages one 10.98
"120.98"
127.0.0.1:6379> HGET ages one
"120.98"
HINCRBYFLOAT key field increment (为哈希表 key 中的指定字段的浮点数值加上增量 increment)
127.0.0.1:6379> HMSET ages one 100 two aini three aini100
OK
127.0.0.1:6379> HKEYS ages
1) "one"
2) "two"
3) "three"
HKEYS key (获取所有哈希表中的字段)
127.0.0.1:6379> HLEN ages
(integer) 3
HLEN key (获取哈希表中字段的数量)
127.0.0.1:6379> HSETNX ages one "1000"    # 存在无法创建
(integer) 0
127.0.0.1:6379> HSETNX ages frou "youyouyou"   # 不存在创建
(integer) 1
127.0.0.1:6379> HGET ages one
"100"
127.0.0.1:6379> HGET ages frou
"youyouyou"
HSETNX key field value (只有在字段 field 不存在时,设置哈希表字段的值)
127.0.0.1:6379> HVALS ages
1) "100"
2) "aini"
3) "aini100"
4) "youyouyou"
HVALS key(获取哈希表中所有值)

4.5 有序集合(Sorted set):

  • Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。 
  • 不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
  • 有序集合的成员是唯一的,但分数(score)却可以重复。
  • 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1).
  • 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

常用有序集合命令具体操作如下:

127.0.0.1:6379> ZADD myzset 1 "one"
(integer) 1
127.0.0.1:6379> ZADD myzset 1 "uno"
(integer) 1
127.0.0.1:6379> ZADD myzset 2 "two" 3 "three"
(integer) 2
127.0.0.1:6379> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
ZADD key score1 member1 [score2 member2] (向有序集合添加一个或多个成员,或者更新已存在成员的分数)
127.0.0.1:6379> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
127.0.0.1:6379> ZCARD myzset
(integer) 4
ZCARD key (获取有序集合的成员数)
127.0.0.1:6379> ZADD myzset 1 "hello"
(integer) 1
127.0.0.1:6379> ZADD myzset 1 "foo"
(integer) 1
127.0.0.1:6379> ZADD myzset 2 "world" 3 "bar"
(integer) 2
127.0.0.1:6379>  ZCOUNT myzset 1 3
(integer) 8
ZCOUNT key min max (计算在有序集合中指定区间分数的成员数)
127.0.0.1:6379> ZADD myzset1 1 "one"
(integer) 1
127.0.0.1:6379> ZADD myzset1 2 "two"
(integer) 1
127.0.0.1:6379> ZINCRBY myzset1 2 "one"
"3"
127.0.0.1:6379> ZRANGE myzset1 0 -1 WITHSCORES
1) "two"
2) "2"
3) "one"
4) "3"
ZINCRBY key increment member (有序集合中对指定成员的分数加上增量 increment)
# 有序集 mid_test
redis 127.0.0.1:6379> ZADD mid_test 70 "Li Lei"
(integer) 1
redis 127.0.0.1:6379> ZADD mid_test 70 "Han Meimei"
(integer) 1
redis 127.0.0.1:6379> ZADD mid_test 99.5 "Tom"
(integer) 1

# 另一个有序集 fin_test
redis 127.0.0.1:6379> ZADD fin_test 88 "Li Lei"
(integer) 1
redis 127.0.0.1:6379> ZADD fin_test 75 "Han Meimei"
(integer) 1
redis 127.0.0.1:6379> ZADD fin_test 99.5 "Tom"
(integer) 1

# 交集
redis 127.0.0.1:6379> ZINTERSTORE sum_point 2 mid_test fin_test
(integer) 3

# 显示有序集内所有成员及其分数值
redis 127.0.0.1:6379> ZRANGE sum_point 0 -1 WITHSCORES     
1) "Han Meimei"
2) "145"
3) "Li Lei"
4) "158"
5) "Tom"
6) "199"
ZINTERSTORE destination numkeys key [key ...] (计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中)
redis 127.0.0.1:6379> ZADD myzset 0 a 0 b 0 c 0 d 0 e
(integer) 5
redis 127.0.0.1:6379> ZADD myzset 0 f 0 g
(integer) 2
redis 127.0.0.1:6379> ZLEXCOUNT myzset - +
(integer) 7
redis 127.0.0.1:6379> ZLEXCOUNT myzset [b [f
(integer) 5
ZLEXCOUNT key min max
redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES             # 显示整个有序集成员
1) "jack"
2) "3500"
3) "tom"
4) "5000"
5) "boss"
6) "10086"

redis 127.0.0.1:6379> ZRANGE salary 1 2 WITHSCORES              # 显示有序集下标区间 12 的成员
1) "tom"
2) "5000"
3) "boss"
4) "10086"

redis 127.0.0.1:6379> ZRANGE salary 0 200000 WITHSCORES         # 测试 end 下标超出最大下标时的情况
1) "jack"
2) "3500"
3) "tom"
4) "5000"
5) "boss"
6) "10086"

redis > ZRANGE salary 200000 3000000 WITHSCORES                  # 测试当给定区间不存在于有序集时的情况
(empty list or set)
ZRANGE key start stop [WITHSCORES] (通过索引区间返回有序集合成指定区间内的成员)
redis 127.0.0.1:6379> ZADD myzset 0 a 0 b 0 c 0 d 0 e 0 f 0 g
(integer) 7
redis 127.0.0.1:6379> ZRANGEBYLEX myzset - [c
1) "a"
2) "b"
3) "c"
redis 127.0.0.1:6379> ZRANGEBYLEX myzset - (c
1) "a"
2) "b"
redis 127.0.0.1:6379> ZRANGEBYLEX myzset [aaa (g
1) "b"
2) "c"
3) "d"
4) "e"
5) "f"
ZRANGEBYLEX key min max [LIMIT offset count] (通过字典区间返回有序集合的成员)
redis 127.0.0.1:6379> ZADD salary 2500 jack                        # 测试数据
(integer) 0
redis 127.0.0.1:6379> ZADD salary 5000 tom
(integer) 0
redis 127.0.0.1:6379> ZADD salary 12000 peter
(integer) 0

redis 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf               # 显示整个有序集
1) "jack"
2) "tom"
3) "peter"

redis 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf WITHSCORES    # 显示整个有序集及成员的 score 值
1) "jack"
2) "2500"
3) "tom"
4) "5000"
5) "peter"
6) "12000"

redis 127.0.0.1:6379> ZRANGEBYSCORE salary -inf 5000 WITHSCORES    # 显示工资 <=5000 的所有成员
1) "jack"
2) "2500"
3) "tom"
4) "5000"

redis 127.0.0.1:6379> ZRANGEBYSCORE salary (5000 400000            # 显示工资大于 5000 小于等于 400000 的成员
1) "peter"
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] (通过分数返回有序集合指定区间内的成员)
redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES        # 显示所有成员及其 score 值
1) "peter"
2) "3500"
3) "tom"
4) "4000"
5) "jack"
6) "5000"

redis 127.0.0.1:6379> ZRANK salary tom                     # 显示 tom 的薪水排名,第二
(integer) 1
ZRANK key member (返回有序集合中指定成员的索引)
# 测试数据

redis 127.0.0.1:6379> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"


# 移除单个元素

redis 127.0.0.1:6379> ZREM page_rank google.com
(integer) 1

redis 127.0.0.1:6379> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"


# 移除多个元素

redis 127.0.0.1:6379> ZREM page_rank baidu.com bing.com
(integer) 2

redis 127.0.0.1:6379> ZRANGE page_rank 0 -1 WITHSCORES
(empty list or set)


# 移除不存在元素

redis 127.0.0.1:6379> ZREM page_rank non-exists-element
(integer) 0
ZREM key member [member ...] (移除有序集合中的一个或多个成员)
redis 127.0.0.1:6379> ZADD myzset 0 aaaa 0 b 0 c 0 d 0 e
(integer) 5
redis 127.0.0.1:6379> ZADD myzset 0 foo 0 zap 0 zip 0 ALPHA 0 alpha
(integer) 5
redis 127.0.0.1:6379> ZRANGE myzset 0 -1
1) "ALPHA"
 2) "aaaa"
 3) "alpha"
 4) "b"
 5) "c"
 6) "d"
 7) "e"
 8) "foo"
 9) "zap"
10) "zip"
redis 127.0.0.1:6379> ZREMRANGEBYLEX myzset [alpha [omega
(integer) 6
redis 127.0.0.1:6379> ZRANGE myzset 0 -1
1) "ALPHA"
2) "aaaa"
3) "zap"
4) "zip"
ZREMRANGEBYLEX key min max (移除有序集合中给定的字典区间的所有成员)
redis 127.0.0.1:6379> ZADD salary 2000 jack
(integer) 1
redis 127.0.0.1:6379> ZADD salary 5000 tom
(integer) 1
redis 127.0.0.1:6379> ZADD salary 3500 peter
(integer) 1

redis 127.0.0.1:6379> ZREMRANGEBYRANK salary 0 1       # 移除下标 01 区间内的成员
(integer) 2

redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES    # 有序集只剩下一个成员
1) "tom"
2) "5000"
ZREMRANGEBYRANK key start stop (移除有序集合中给定的排名区间的所有成员)
redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES          # 显示有序集内所有成员及其 score 值
1) "tom"
2) "2000"
3) "peter"
4) "3500"
5) "jack"
6) "5000"

redis 127.0.0.1:6379> ZREMRANGEBYSCORE salary 1500 3500      # 移除所有薪水在 15003500 内的员工
(integer) 2

redis> ZRANGE salary 0 -1 WITHSCORES          # 剩下的有序集成员
1) "jack"
2) "5000"
ZREMRANGEBYSCORE key min max (移除有序集合中给定的分数区间的所有成员)
redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES        # 递增排列
1) "peter"
2) "3500"
3) "tom"
4) "4000"
5) "jack"
6) "5000"

redis 127.0.0.1:6379> ZREVRANGE salary 0 -1 WITHSCORES     # 递减排列
1) "jack"
2) "5000"
3) "tom"
4) "4000"
5) "peter"
6) "3500"
ZREVRANGE key start stop [WITHSCORES] (返回有序集中指定区间内的成员,通过索引,分数从高到底)
redis 127.0.0.1:6379> ZADD salary 10086 jack
(integer) 1
redis > ZADD salary 5000 tom
(integer) 1
redis 127.0.0.1:6379> ZADD salary 7500 peter
(integer) 1
redis 127.0.0.1:6379> ZADD salary 3500 joe
(integer) 1

redis 127.0.0.1:6379> ZREVRANGEBYSCORE salary +inf -inf   # 逆序排列所有成员
1) "jack"
2) "peter"
3) "tom"
4) "joe"

redis 127.0.0.1:6379> ZREVRANGEBYSCORE salary 10000 2000  # 逆序排列薪水介于 100002000 之间的成员
1) "peter"
2) "tom"
3) "joe"
ZREVRANGEBYSCORE key max min [WITHSCORES] (返回有序集中指定分数区间内的成员,分数从高到低排序)
redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES     # 测试数据
1) "jack"
2) "2000"
3) "peter"
4) "3500"
5) "tom"
6) "5000"

redis 127.0.0.1:6379> ZREVRANK salary peter     # peter 的工资排第二
(integer) 1

redis 127.0.0.1:6379> ZREVRANK salary tom       # tom 的工资最高
(integer) 0
ZREVRANK key member (返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序)
redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES    # 测试数据
1) "tom"
2) "2000"
3) "peter"
4) "3500"
5) "jack"
6) "5000"

redis 127.0.0.1:6379> ZSCORE salary peter              # 注意返回值是字符串
"3500"
ZSCORE key member (返回有序集中,成员的分数值)
redis 127.0.0.1:6379> ZRANGE programmer 0 -1 WITHSCORES
1) "peter"
2) "2000"
3) "jack"
4) "3500"
5) "tom"
6) "5000"

redis 127.0.0.1:6379> ZRANGE manager 0 -1 WITHSCORES
1) "herry"
2) "2000"
3) "mary"
4) "3500"
5) "bob"
6) "4000"

redis 127.0.0.1:6379> ZUNIONSTORE salary 2 programmer manager WEIGHTS 1 3   # 公司决定加薪。。。除了程序员。。。
(integer) 6

redis 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES
1) "peter"
2) "2000"
3) "jack"
4) "3500"
5) "tom"
6) "5000"
7) "herry"
8) "6000"
9) "mary"
10) "10500"
11) "bob"
12) "12000"
ZUNIONSTORE destination numkeys key [key ...] (计算给定的一个或多个有序集的并集,并存储在新的 key 中)

5.Redis的发布订阅

  • Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
  • Redis 客户端可以订阅任意数量的频道。

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

具体实例:

创建订阅频道名为 redisChat:

127.0.0.1:6379> SUBSCRIBE redisChat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1

现在,我们先重新开启个 redis 客户端,然后在同一个频道 redisChat 发布两次消息,订阅者就能接收到消息。 

# 发布的两次消息
127.0.0.1:6379> PUBLISH redisChat "hello world"
(integer) 1
127.0.0.1:6379> PUBLISH redisChat "Nice to meet you"
(integer) 1


# 订阅者接收到的信息
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1
1) "message"
2) "redisChat"
3) "hello world"
1) "message"
2) "redisChat"
3) "Nice to meet you"

6.Redis的HyperLogLog

  • Redis HyperLogLog是用来做基数统计的算法。
  • 优点是:在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
  • 在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

注:因为HyperLogLog只会根据输入元素来计算基数,而不会存储输入元素本身,因此不会返回输入的各个元素。

基数是什么?

  对于["abc", "abc", "2", "3"],基数是["abc", "2", "3"],个数是3.

具体实例如下:

127.0.0.1:6379> pfadd jsh redis
(integer) 1
127.0.0.1:6379> pfadd jsh redis
(integer) 0
127.0.0.1:6379> pfadd jsh mongodb
(integer) 1
127.0.0.1:6379> pfadd jsh rabbitmq
(integer) 1
127.0.0.1:6379> pfcount jsh
(integer) 3
127.0.0.1:6379> pfadd jsh2 redis
(integer) 1
127.0.0.1:6379> pfadd jsh2 a
(integer) 1
127.0.0.1:6379> pfcount jsh2
(integer) 2

127.0.0.1:6379> pfmerge jsh jsh2
OK
127.0.0.1:6379> pfcount jsh
(integer) 4
127.0.0.1:6379> pfcount jsh2
(integer) 2

注:

  • pfadd key ele [ele2 ...]:添加指定元素到HyperLogLog中。
  • pfcount key: 返回给定HyperLogLog的基数估算值。
  • pfmerge destkey srckey [srckey2....]:讲多个HyperLogLog合并到一个第一个HyperLogLog中。

7.Redis的事务

Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证:

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

一个事务从开始到执行会经历以下三个阶段:

  • 开始事务
  • 命令入队
  • 执行事务

以下是一个事务的例子, 它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET qq-name "python love you"
QUEUED
127.0.0.1:6379> GET qq-name
QUEUED
127.0.0.1:6379> SADD tag "java" "php" "c++"
QUEUED
127.0.0.1:6379> SMEMBERS tag
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) "python love you"
3) (integer) 3
4) 1) "c++"
   2) "java"
   3) "php"

单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

比如:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET a aaa
QUEUED
127.0.0.1:6379> SET b bbb
QUEUED
127.0.0.1:6379> SET c ccc
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
3) OK

注:如果在 set b bbb 处失败,set a 已成功不会回滚,set c 还会继续执行。 

redis 事务的相关命令:

  • DISCARD  :取消事务,放弃执行事务块内的所有命令。
  • EXEC :执行所有事务块内的命令。
  • MULTI :标记一个事务块的开始。
  • UNWATCH :取消 WATCH 命令对所有 key 的监视。
  • WATCH key [key ...] :监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

8.Redis的脚本

Redis 脚本使用 Lua 解释器来执行脚本。执行脚本的常用命令为 EVAL。基本语法:

EVAL script numkeys key [key ...] arg [arg ...]

具体实例:

127.0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first seconde
1) "key1"
2) "key2"
3) "first"
4) "seconde"

9.Redis的数据备份与恢复

9.1 备份数据:

Redis SAVE 命令用于创建当前数据库的备份

语法:

127.0.0.1:6379> SAVE

具体实例:

127.0.0.1:6379> SAVE
OK
127.0.0.1:6379> 

注:该命令将在 redis 安装目录中创建dump.rdb文件

9.2 恢复数据:

如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可。获取 redis 目录可以使用 CONFIG 命令,如下所示:

127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "/root/redis-4.0.8"
127.0.0.1:6379> 

以上命令 CONFIG GET dir 输出的 redis 安装目录为:/root/redis-4.0.8 

9.3 后台执行备份:

创建 redis 备份文件也可以使用命令 BGSAVE,该命令在后台执行。

127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> 

10.Redis数据库操作

Redis中,一共有16个数据库,分别是0~15,一般情况下,进入数据库默认编号是0

如果我们要进入指定数据库,可以用select语句:

切换到编号为6的数据库:

127.0.0.1:6379> SELECT 6
OK
127.0.0.1:6379[6]> 

查看数据库中所有的键值:

# 因为编号6 中没有数据 所以先临时新建几个
127.0.0.1:6379[6]> SET a 1
OK
127.0.0.1:6379[6]> SET b 2
OK
127.0.0.1:6379[6]> SET c 3
OK
127.0.0.1:6379[6]> KEYS *
1) "b"
2) "a"
3) "c"

返回当前数据库中所有key的数目:  dbsize 

删除当前数据库中的所有key:   flushdb    

清空所有数据库中的所有key:   flushall

把当前数据库中的key转移到指定数据库:move a aim_db,例:

127.0.0.1:6379[6]> set z qqq
OK
127.0.0.1:6379[6]> MOVE z 0
(integer) 1
127.0.0.1:6379[6]> SELECT 0
OK
127.0.0.1:6379> GEt z
"qqq"

11.Redis管道技术(哈哈 还在学习中)

12.Redis分区

分区是分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集。

12.1 分区的优势:

  • 通过利用多台计算机内存的和值,允许我们构造更大的数据库。
  • 通过多核和多台计算机,允许我们扩展计算能力;通过多台计算机和网络适配器,允许我们扩展网络带宽。

12.2 分区的劣势:

  • 涉及多个key的操作通常是不被支持的。举例来说,当两个set映射到不同的redis实例上时,你就不能对这两个set执行交集操作。
  • 涉及多个key的redis事务不能使用。
  • 当使用分区时,数据处理较为复杂,比如你需要处理多个rdb/aof文件,并且从多个实例和主机备份持久化文件。
  • 增加或删除容量也比较复杂。redis集群大多数支持在运行时增加、删除节点的透明数据平衡的能力,但是类似于客户端分区、代理等其他系统则不支持这项特性。然而,一种叫做presharding的技术对此是有帮助的。

12.3 分区的类型:

Redis 有两种类型分区。 假设有4个Redis实例 R0,R1,R2,R3,和类似user:1,user:2这样的表示用户的多个key,对既定的key有多种不同方式来选择这个key存放在哪个实例中。也就是说,有不同的系统来映射某个key到某个Redis服务。

  • 范围分区:

  最简单的分区方式是按范围分区,就是映射一定范围的对象到特定的Redis实例。

  比如,ID从0到10000的用户会保存到实例R0,ID从10001到 20000的用户会保存到R1,以此类推。

  这种方式是可行的,并且在实际中使用,不足就是要有一个区间范围到实例的映射表。这个表要被管理,同时还需要各 种对象的映射表,通常对Redis来说并非是好的方法。

  • 哈希分区:

  另外一种分区方法是hash分区。这对任何key都适用,也无需是object_name:这种形式,像下面描述的一样简单:

    • 用一个hash函数将key转换为一个数字,比如使用crc32 hash函数。对key foobar执行crc32(foobar)会输出类似93024922的整数。
    • 对这个整数取模,将其转化为0-3之间的数字,就可以将这个整数映射到4个Redis实例中的一个了。93024922 % 4 = 2,就是说key foobar应该被存到R2实例中。注意:取模操作是取除的余数,通常在多种编程语言中用%操作符实现。

13.Redis性能测试

Redis 性能测试是通过同时执行多个命令实现的。

语法:

redis-benchmark [option] [option value]

具体实例:

以下实例同时执行 10000 个请求来检测性能:

[root@BrianZhu redis-4.0.8]# src/redis-benchmark -n 10000  -q
PING_INLINE: 94339.62 requests per second
PING_BULK: 92592.59 requests per second
SET: 91743.12 requests per second
GET: 90090.09 requests per second
INCR: 97087.38 requests per second
LPUSH: 96153.84 requests per second
RPUSH: 96153.84 requests per second
LPOP: 97087.38 requests per second
RPOP: 97087.38 requests per second
SADD: 96153.84 requests per second
HSET: 93457.95 requests per second
SPOP: 97087.38 requests per second
LPUSH (needed to benchmark LRANGE): 94339.62 requests per second
LRANGE_100 (first 100 elements): 95238.10 requests per second
LRANGE_300 (first 300 elements): 95238.10 requests per second
LRANGE_500 (first 450 elements): 96153.84 requests per second
LRANGE_600 (first 600 elements): 78740.16 requests per second
MSET (10 keys): 83333.34 requests per second

14.Redis关闭持久化(单纯的做缓存)

数据持久化是Redis不同于其他缓存的一个特性,具有明显的有点。但如不希望持久化数据,只作为普通的缓存用,如memcache

方法:

将配置文件中关于save配置信息全部注释,如下:

#save 900 1  
#save 300 10  
#save 60 10000  

或执行操作命令:

CONFIG SET save ""

执行命令后,无需重启即可生效

15.Redis可视化工具

都到这里了 肯定命令都已经玩腻了吧  现在来新菜了  那就是Redis的可视化工具 它的名字叫:RedisDesktopManager  下载地址:https://redisdesktop.com/download

安装连接就很简单了  和windows的其他软件一样 下一步 下一步就好了  软件是全英文的  但是看懂也不需要太好的英文水平  其实我就是个英文盲  下面就贴几张图 结束吧

 

原文地址:https://www.cnblogs.com/brianzhu/p/8733050.html