“Redis:常用命令”的版本间差异

来自Wikioe
跳到导航 跳到搜索
第360行: 第360行:


== 事务 ==
== 事务 ==
=== 什么是事务 ===
事务:是指一系列操作步骤,要么完全地执行,要么完全地不执行。 <br/>
Redis中的事务(transaction)是一组命令的集合,至少是两个或两个以上的命令,redis事务保证这些命令被执行时中间不会被任何其他操作打断。<br/>
示例:微博中,A用户关注了B用户,那么A的关注人列表里面就会有B用户,B的粉丝列表里面就会有A用户。
:这个关注与被关注的过程是由一系列操作步骤构成:
# A用户添加到B的粉丝列表里面;
# B用户添加到A的关注列表里面;
这两个步骤必须全部执行成功,整个逻辑才是正确的,否则就会产生数据的错误,比如A用户的关注列表有B用户,但B的粉丝列表里没有A用户;
=== redis事务控制 ===
* 正常情况
# MULTI:用MULTI命令告诉Redis,接下来要执行的命令你先不要执行,而是把它们暂时存起来 (开启事务)
# SADD "user1" 2:第一条命令进入等待队列(命令入队)
# SADD "user2" 1:第二条命令进入等待队列(命令入队)
# EXEC:告知redis执行前面发送的两条命令(提交事务)
* 异常情况
# MULTI:正常命令
# SET key value:正常命令
# SET key:命令语法错误
# EXEC:无法执行事务,那么第一条正确的命令也不会执行,所以key的值不会设置成功
* 例外情况
# MULTI:正常命令
# SET key v1:正常命令
# INCR key:此命令错误,字符串不能自增
# EXEC:
## 事务依然提交了,key的值被设置为v1,自增操作执行失败,但整个事务没有回滚
## 可以放弃事务:discard
* 放弃情况
# MULTI:开启事务
# SET age 25:命令入队
# SET age 30:命令入队
# DISCARD:放弃事务,则命令队列不会被执行
=== redis事务复杂情况实现 ===
==== 悲观锁 ====
悲观锁(Pessimistic Lock):每次去拿数据的时候都认为别人会修改该数据,所以每次在拿数据的时候都会先上锁,这样别人想拿这个数据就会block阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁,让别人无法操作该数据。
==== 乐观锁 ====
乐观锁(Optimistic Lock):每次去取数据的时候都认为别人不会修改该数据,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这条数据,一般使用版本号机制进行判断。乐观锁适用于多读的应用类型,这样可以提高吞吐量。
* 乐观锁大多数情况是基于数据版本号(version)的机制实现的:为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表添加一个“version”字段来实现读取出数据时,将此版本号一同读出,之后更新时,对此版本号加1。此时,将提交数据的版本号与数据库表对应记录的当前版本号进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据,不予更新。
:乐观锁实现举例:
:[[File:乐观锁实现举例.png|600px]]
==== redis的watch机制实现乐观锁 ====
监视一个(或多个) key ,'''如果在事务exec执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断'''。
示例:
# set k1 1:设置k1值为1
# watch k1:监视k1 (当已经开始监控k1,则其他客户端不能修改k1的值)
# set k1 2:设置k1值为2
# multi:开始事务
# set k1 3:修改k值为3
# exec:提交事务,但k1值不会被修改为3,k1的值仍然是2,因为在事务开启之前k1的值被修改了


== 持久化 ==
== 持久化 ==

2020年10月28日 (三) 00:59的版本


关于Redis

Remote Dictionary Server(Redis) 是一个开源的由Salvatore Sanfilippo使用ANSI C语言编写的key-value数据存储服务器。其值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型,所以它通常也被称为数据结构服务器。

  • redis属于NoSQL数据库,NoSQL数据库叫非关系型数据库,(NoSQL = Not Only SQL),意即"不仅仅是SQL"。
  • 数据库类型:
    1. key-value存储:“Berkeley DB”、“MemcacheDB”、“Redis”
    2. 文档存储:“MongoDB”、“CouchDB”
    3. 列存储:“Hbase”、“Cassandra”


redis的特点:

  1. redis足够简单和稳定
  2. 支持丰富的数据结构
  3. 内存存储读写性能优秀
  4. 提供持久化的支持
  5. 支持部分事务操作

下载安装

  • 安装:
    1. 解压:tar -zxvf redis-3.2.9.tar.gz
    2. 切换目录: cd redis-3.2.9,执行命令:make
    3. 将 src下的可执行文件复制到/usr/local/bin 目录下,再执行 make install
  • 启动:(切换到 redis-3.2.9/src/ 目录执行命令)
    • 后台启动:“./redis-server & ”
    • 后台启动并输出日志到nohup.out文件:“nohup /usr/local/redis-3.2.9/src/redis-server &”
  • 关闭:(结束进程:kill pid 或者 kill -9 pid)
    • 切换到 redis-3.2.9/src/ 目录执行:“./redis-cli shutdown”

客户端

redis命令行客户端:

  1. redis-cli(Redis Command Line Interface)是Redis自带的基于命令行的Redis客户端,用于与服务端交互,我们可以使用该客户端来执行redis的各种命令。
    • 直接连接redis (默认ip127.0.0.1,端口6379):“./redis-cli”
    • 指定IP和端口连接redis:“./redis-cli -h 127.0.0.1 -p 6379”


redis远程客户端:

  1. Redis Desktop Manager
    • 官网:https://redisdesktop.com/
    • 远程连接redis需要修改redis主目录下的“redis.conf”配置文件:
      1. “bind ip”绑定ip注释掉;
      2. “protected-mode yes”保护模式改为no;
  2. phpRedisAdmin
    • (需要本地安装php运行环境)


redis编程客户端(Java):(类似于数据库驱动)使用它提供的API就能访问服务器上的redis并对它进行各种操作。

  1. Jedis,redis的Java编程客户端,Redis官方首选推荐使用Jedis,jedis是一个很小但很健全的redis的java客户端
  2. Lettuce:可伸缩线程安全的Redis客户端。多个线程可以共享同一个“RedisConnection”。它利用优秀netty NIO框架来高效地管理多个连接。
  • redis的其他编程语言客户端:C、C++、C#、Erlang、Lua、Objective-C、Perl、PHP、Python、Ruby、Scala、Go,等40多种语言都有连接redis的编程客户端;

Redis基础

  • “redis.conf”是Redis的配置文件;
  • redis默认为16个库(默认自动使用0号库);


redis手册:


基础命令:

  1. 验证安装:(redis-cli等链接后)输入“ping”(redis返回“PONG”表示服务运行正常);
  2. 切换库命令:“select <db>”;
  3. 删除所有库的数据:“flushall”;
  4. 删除当前库的数据:“flushdb”;
  5. 获得redis的所有配置值:“config get *”;
  6. redis-cli退出当前redis连接:“exit”或“quit”;
  7. 查看当前数据库中key的数目:“dbsize”;
  8. 查看redis服务器的统计信息:“info”;

1 + 5 命令:

  • 1种key操作:“key”命令,redis以key-value存储数据,所有的操作均为对key的操作:
命令 说明
keys * 列出所有的key
exists <key> 检查某个key是否存在
move <key> db 将当前库的key移动到给定的库db中,比如:move k1 2
expire <key> seconds 设置key的值的过期时间
ttl <key> ttl(time to live)查看key还有多少秒过期,-1永不过期,-2已过期或key不存在
type <key> 查看key所储存的值的类型
del <key> 删除key
  • 5种数据类型操作:
数据类型 说明
string 字符串类型
hash 哈希类型
list 列表类型
set 集合类型
zset(sorted set) 有序集合类型

Java操作redis

  • jedis的jar包依赖Maven配置:(jedis也依赖“Apache Commons Pool 2 2.0”)
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
    </dependency>
    
  • 使用jedis:
       public static void main(String[] args) {
          //连接Redis服务器
          Jedis jedis = new Jedis("192.168.1.103", 6379);
          //查看服务是否运行正常
          System.out.println("服务正在运行: " + jedis.ping());
       }
    

5种数据类型

string

字符串类型:字符串类型是Redis中最基本的数据类型;

  • 它能存储任何形式的字符串,包括二进制数据,序列化后的数据,JSON化的对象甚至是一张图片。
Redis-string.png
命令 说明
set <key> <value> 将字符串值 value 设置到 key 中;
get <key> 获取 key 中设置的字符串值;
incr <key> 将 key 中储存的数字值加1;
  • 如果 key 不存在,则 key 的值先被初始化为 0 再执行 INCR 操作;
  • (只能对数字类型的数据操作,否则:“(error) ERR value is not an integer or out of range”);
decr <key> 将 key 中储存的数字值减1;
  • (同上,两条);
setex <key> <seconds> <value> set expire”的简写,设置key的值 ,并将 key 的生存时间设为 seconds (以秒为单位) ;
setnx <key> <value> setnx 是“set if not exists”的简写,如果key不存在,则设置值,存在则不设置值;
getset <key> <value> 设置 key 的值为 value ,并返回 key 的旧值;
strlen <key> 返回 key 所储存的字符串值的长度;
append <key> <value> 如果 key 存在且是字符串, 则将 value 追加到 key 原来旧值的末尾;
  • 如果 key 不存在, 则将key 设置值为 value;
incrby <key> <increment> 将 key 所储存的值加上增量值;
  • 如果 key 不存在,则 key 的值先被初始化为 0 再执行 INCRBY 命令;
decrby <key> <decrement> 将 key 所储存的值减去减量值;
  • 如果 key 不存在,则 key 的值先被初始化为 0 再执行 DECRBY 命令;
getrange <key> <start> <end> 获取 key 中字符串值从 start 开始 到 end 结束 的子字符串;
setrange <key> <offset> <value> 从指定的位置开始将key的值替换为新的字符串;
mset <key> <value> [<key> <value>] 同时设置一个或多个 key-value 对
mget <key> [<key>] 获取所有(一个或多个)给定 key 的值
msetnx <key> <value> [<key> <value>] 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在时才能设置成功,否则只要有一个key存在都会失败

hash

哈希类型:是一个string类型的field和value的映射表;

  • hash特别适合用于存储对象
Redis-hash.png

(命令前加了“h”,对“key”及“field(域)”和“value”操作)

命令 说明
hset <key> <field> <value> 将哈希表 key 中的域 field 的值设为 value
hget <key> <field> 获取哈希表 key 中给定域 field 的值
hmset <key> <field> <value> [<field> <value>] 同时将多个 field-value (域-值)对设置到哈希表 key 中
hmget <key> <field> [<field>] 获取哈希表 key 中一个或多个给定域的值
hgetall <key> 获取哈希表 key 中所有的域和值
hdel <key> <field> [<field>] 删除哈希表 key 中的一个或多个指定域field
hkeys <key> 查看哈希表 key 中的所有field域
hvals <key> 查看哈希表 key 中所有域的值
hlen <key> 获取哈希表 key 中域field的个数
hexists <key> <field> 查看哈希表 key 中,给定域 field 是否存在
hincrby <key> <field> <increment> 为哈希表 key 中的域 field 的值加上增量 increment
hincrbyfloat <key> <field> <increment> 为哈希表 key 中的域 field 加上浮点数增量 increment
hsetnx <key> <field> <value> 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在的时候才设置,否则不设置

list

列表类型:简单的字符串列表,按照插入顺序排序。

  • 可以添加一个元素导列表的头部(左边)或者尾部(右边);【???】
Redis-list.png

(命令前加了“l”,,对“key”和“value”操作,对元素进行类似于队列的操作)

命令 说明
lpush <key> <value> [<value>] 将一个或多个值 value 插入到列表 key 的表头(最左边)
rpush <key> <value> [<value>] 将一个或多个值 value 插入到列表 key 的表尾(最右边)
lrange <key> <start> <stop> 获取列表 key 中指定区间内的元素
  • 0 表示列表的第一个元素,以 1 表示列表的第二个元素, -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
lpop <key> 从左边获取列表 key 的一个元素,并将该元素移除
rpop <key> 从右边获取列表 key 的一个元素,并将该元素移除
lindex <key> <index> 获取列表 key 中下标为指定 index 的元素
llen <key> 获取列表 key 的长度
lrem <key> <count> <value> 从左到右删除列表中指定个数的“与指定value值相等的”value
ltrim <key> <start> <stop> 删除指定区域外的元素,比如LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除
rpoplpush <source> <destination> “RPOPLPUSH source destination”将列表 source 中的最后一个元素(尾元素)弹出插入到列表 destination ,作为 destination 列表的的头元素
lset <key> <index> <value> 将列表 key 下标为 index 的元素的值设置为 value
linsert <key> BEFORE|AFTER <pivot> <value> 将值 value 插入到列表 key 当中位于值 pivot 之前或之后的位置

set

集合类型:string类型的无序集合,集合成员是唯一的,即集合中不能出现重复的数据;

Redis-set.png

(命令前加了“s”,对“key”和“member”操作)

命令 说明
sadd <key> <member> [<member>] 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将不会再加入
smembers <key> 获取集合 key 中的所有成员元素
sismember <key> <member> 判断 member 元素是否是集合 key 的成员
scard <key> 获取集合里面的元素个数
srem <key> <member> [<member>] 删除集合 key 中的一个或多个 member 元素
srandmember <key> [count] 随机返回集合中的一个元素【???】
spop <key> [count] 随机从集合中删除一个元素
smove <source> <destination> <member> 将 member 元素从一个集合移动到另一个集合

zset(sorted set)

有序集合类型:(有序的set)不同的是zset的每个元素都会关联一个分数(分数可以重复),redis通过分数来为集合中的成员进行从小到大的排序。

Redis-zset.png

(命令前加了“z”,对“key”及“member”和“score”操作)

命令 说明
XX] [CH] [INCR] <score> <member> [<score> <member>] 将一个或多个 member 元素及其 score 值加入到有序集合 key 中
zrem <key> <member> [<member>] 删除有序集合 key 中的一个或多个成员
zcard <key> 获取有序集 key 的元素成员的个数
zrank <key> <member> 获取有序集 key 中成员 member 的排名,有序集成员按 score 值从小到大顺序排列
zrevrank <key> <member> 获取有序集 key 中成员 member 的排名,有序集成员按 score 值从大到小顺序排列
zrangebyscore <key> <min> <max> [WITHSCORES] [LIMIT offset count] 获取有序集 key 中,所有 score 值介于 min 和 max 之间的成员【有啥区别】
zrevrangebyscore <key> <min> <max> [WITHSCORES] [LIMIT offset count] 获取有序集 key 中, score 值介于 max 和 min 之间的所有的成员【有啥区别】
zcount <key> <min> <max> 获取有序集 key 中,所有 score 值介于 min 和 max 之间的成员的个数
zrange <key> <start> <stop> [WITHSCORES] 获取有序集 key 中,指定区间内的成员,按 score 值从小到大排列【?】
zrevrange <key> <start> <stop> [WITHSCORES] 获取有序集 key 中,指定区间内的成员,按 score 值从大到小排列【?】

发布和订阅

发布订阅是消息队列的一种方式,基于消息队列的方式,可以实现系统解耦、削峰填谷,顶住流量洪峰;

  • redis的主业目前是基于键值对的数据存储、缓存等,消息队列可能是redis的一种尝试;
  • 常用的流行的消息队列有:“ActiveMQ”、“RabbitMQ”等;


什么是发布订阅

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(publish)发送消息,订阅者(subscribe)接收消息。

  • 发布订阅也叫“生产者消费者”模式,是实现“消息队列”的一种方式;
  • 消息队列的三要素:
    1. 生产者(producer)
    2. 消费者(consumer)
    3. 消息服务(broker)
    Redis发布和订阅关系图.png


发布:

Redis发布.png

订阅:

Reids订阅.png

如何实现

(以命令行模拟实现)

  1. 开启4个redis客户端(“./redis-cli”),如上图,3个客户端作为消息订阅者,1个为消息发布者:
  2. 让3个消息订阅者订阅某个频道主题:“subscribe channelTest”;(命令:“subscribe channel [channel ...]”)
    Redis订阅channelTest.jpg
  3. 让1个消息发布者向频道主题上发布消息:“publish channelTest message123”;(命令“publish channel message”)
    Redis发布消息到channelTest.jpg


  • 如果是订阅匹配模式的频道主题:“psubscribe chan*”(表示匹配以chan开头的频道主题,命令“ psubscribe pattern [pattern ...]”);
    订阅:
    Redis订阅(psubscribe).jpg
    发布:
    Redis发布(psubscribe).jpg

事务

什么是事务

事务:是指一系列操作步骤,要么完全地执行,要么完全地不执行。
Redis中的事务(transaction)是一组命令的集合,至少是两个或两个以上的命令,redis事务保证这些命令被执行时中间不会被任何其他操作打断。


示例:微博中,A用户关注了B用户,那么A的关注人列表里面就会有B用户,B的粉丝列表里面就会有A用户。

这个关注与被关注的过程是由一系列操作步骤构成:
  1. A用户添加到B的粉丝列表里面;
  2. B用户添加到A的关注列表里面;

这两个步骤必须全部执行成功,整个逻辑才是正确的,否则就会产生数据的错误,比如A用户的关注列表有B用户,但B的粉丝列表里没有A用户;

redis事务控制

  • 正常情况
  1. MULTI:用MULTI命令告诉Redis,接下来要执行的命令你先不要执行,而是把它们暂时存起来 (开启事务)
  2. SADD "user1" 2:第一条命令进入等待队列(命令入队)
  3. SADD "user2" 1:第二条命令进入等待队列(命令入队)
  4. EXEC:告知redis执行前面发送的两条命令(提交事务)
  • 异常情况
  1. MULTI:正常命令
  2. SET key value:正常命令
  3. SET key:命令语法错误
  4. EXEC:无法执行事务,那么第一条正确的命令也不会执行,所以key的值不会设置成功
  • 例外情况
  1. MULTI:正常命令
  2. SET key v1:正常命令
  3. INCR key:此命令错误,字符串不能自增
  4. EXEC:
    1. 事务依然提交了,key的值被设置为v1,自增操作执行失败,但整个事务没有回滚
    2. 可以放弃事务:discard
  • 放弃情况
  1. MULTI:开启事务
  2. SET age 25:命令入队
  3. SET age 30:命令入队
  4. DISCARD:放弃事务,则命令队列不会被执行

redis事务复杂情况实现

悲观锁

悲观锁(Pessimistic Lock):每次去拿数据的时候都认为别人会修改该数据,所以每次在拿数据的时候都会先上锁,这样别人想拿这个数据就会block阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁,让别人无法操作该数据。

乐观锁

乐观锁(Optimistic Lock):每次去取数据的时候都认为别人不会修改该数据,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这条数据,一般使用版本号机制进行判断。乐观锁适用于多读的应用类型,这样可以提高吞吐量。

  • 乐观锁大多数情况是基于数据版本号(version)的机制实现的:为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表添加一个“version”字段来实现读取出数据时,将此版本号一同读出,之后更新时,对此版本号加1。此时,将提交数据的版本号与数据库表对应记录的当前版本号进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据,不予更新。
乐观锁实现举例:
文件:乐观锁实现举例.png

redis的watch机制实现乐观锁

监视一个(或多个) key ,如果在事务exec执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断


示例:

  1. set k1 1:设置k1值为1
  2. watch k1:监视k1 (当已经开始监控k1,则其他客户端不能修改k1的值)
  3. set k1 2:设置k1值为2
  4. multi:开始事务
  5. set k1 3:修改k值为3
  6. exec:提交事务,但k1值不会被修改为3,k1的值仍然是2,因为在事务开启之前k1的值被修改了

持久化

集群

安全