Redis学习笔记(4) Redis事务、生存时间及排序

时间:2022-03-21 20:02:55

1. Redis事务
  Redis中的事务(transaction)是一组命令的集合,一个事务中的命令要么都执行,要么都不执行。事务的原理是先将属于一个事务的命令发送给Redis,然后再让Redis依次执行这些命令。

127.0.0.1:> multi
OK
127.0.0.1:> sadd user::following
QUEUED
127.0.0.1:> sadd user::followers
QUEUED
127.0.0.1:> EXEC
) (integer)
) (integer)

  multi命令告诉redis,发送的sadd命令属于同一个事务,先将其暂存起来,随后Redis没有执行这些命令,返回QUEUE表示这两条命令已进入等待执行的事务队列。EXEC命令将等待执行的事务队列中的所有命令按发送顺序依次执行,其返回值为这些命令的返回值组成的列表。
  若在发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的所有命令均不执行;客户端若发送了EXEC命令,即使客户端断线,事务队列中的命令也会执行。Redis中的事务也能保证一个事务内的命令依次执行而不被其他命令插入。

  (1) 错误处理
  1) 语法错误,当命令不存在或命令参数个数不对。只要一个命令有语法错误,执行EXEC命令后Redis就会直接返回错误,语法正确也不会执行。
  例:

127.0.0.1:> MULTI
OK
127.0.0.1:> SET key value
QUEUED
127.0.0.1:> SET key
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:> ERRORCOMMAND key
(error) ERR unknown command 'ERRORCOMMAND'
127.0.0.1:> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:>

  2) 运行错误,指在命令执行时出现的错误,在事务中这样的命令会被Redis接受并执行,若事务中一条命令出现运行错误,其他命令依然会执行。
    例:

127.0.0.1:> MULTI
OK
127.0.0.1:> SET key
QUEUED
127.0.0.1:> SADD key
QUEUED
127.0.0.1:> SET key
QUEUED
127.0.0.1:> EXEC
) OK
) (error) WRONGTYPE Operation against a key holding the wrong kind of value
) OK

注:Redis的事务没有关系数据库事务提供的回滚(rollback)功能。

   (2) WATCH命令
  在某些情况下,需要先获得一条命令的返回值,然后再根据该值执行下一条命令。WAHCH命令可以监控一个或多个键,一旦其中有一个键被修改,之后的事务就不会执行。监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,所以在MULTI命令后可以修改WATCH监控的键值)。
例:

127.0.0.1:> SET key
OK
127.0.0.1:> WATCH key
OK
127.0.0.1:> SET key
OK
127.0.0.1:> MULTI
OK
127.0.0.1:> SET key
QUEUED
127.0.0.1:> EXEC
(nil)

例:通过事务实现incr函数

    def incr($key)
WATCH $key
$value = GET $key
if not $value
$value =
$value = $value +
MULTI
SET $key $value
result = EXEC
return result[]

  执行EXEC命令后会取消对所有键的监控,若不想执行事务中的命令也可以使用UNWATCH命令来取消监控。
例:实现与HSETNX命令类似的函数hsetxx

    def hsetxx($key,$field,$value)
WATCH $key
$isFieldExists = HEXISTS $key, $field
# 判断要赋值的字段是否存在
if $isFieldExists is
MULTI
HSET $key, $field, $value
EXEC
else
#不存在时需使用UNWATCH保证下一个事务的执行不回受到影响。
UNWATCH
return $isFieldExists

2. 生存时间
    (1) 在Redis中可以使用EXPIRE命令设置一个键的生存时间,到时间后Redis会自动删除它。格式为:EXPIRE key seconds,seconds参数表示键的生存时间,单位是秒。
例:

127.0.0.1:> set session:29e3d uid1314
OK
# 设置键在15分钟被删除,返回1表示设置成功,返回0表示不存在或设置失败
127.0.0.1:> EXPIRE session:29e3d
(integer)
127.0.0.1:> del session:29e3d
(integer)
127.0.0.1:> EXPIRE session:29e3d
(integer)

  可以使用TTL命令查询键的剩余时间。注意:返回值为-1时表示没有为键设置生存时间,即永久存在。
例:

127.0.0.1:> SET foo bar
OK
127.0.0.1:> EXPIRE foo
(integer)
127.0.0.1:> TTL foo
(integer)
#当键不存在时TTL命令会返回-
127.0.0.1:> TTL foo
(integer) -

  使用PERSIST命令可以取消键的生存时间设置,生存时间成功清除返回1。
例:

127.0.0.1:> set foo bar
OK
127.0.0.1:> EXPIRE foo
(integer)
127.0.0.1:> ttl foo
(integer)
127.0.0.1:> PERSIST foo
(integer)
127.0.0.1:> TTL foo
(integer) -

  使用SET或GETSET命令为键赋值也会同时清除键的生存时间,如:

127.0.0.1:> EXPIRE foo
(integer)
127.0.0.1:> TTL foo
(integer)
127.0.0.1:> SET foo bar
OK
127.0.0.1:> TTL foo
(integer) -

  使用EXPIRE命令会重新设置键的生存时间,其余只对键进行操作的命令均不会影响键的生存时间。
  EXPIRE命令的seconds参数最小单位是1秒,PEXPIRE命令的单位是毫秒,对应的可以使用PTTL命令以毫秒为单位返回键的剩余时间。
  若使用WATCH命令监测一个拥有生存时间的键,该键时间到期自动删除并不会被WATCH命令认为该键被改变。
  EXPIREAT(PEXPIREAT)与EXPIRE(PEXPIRE)的差别在于前者使用UNIX时间戳作为生存时间的截止时间,如:

127.0.0.1:> SET foo bar
OK
127.0.0.1:> EXPIRE foo
(integer)
127.0.0.1:> TTL foo
(integer)
127.0.0.1:> PEXPIRE foo
(integer)
127.0.0.1:> TTL foo
(integer)

  (2) 实现访问频率
  限制每分钟每个用户最多只能访问100个页面:

$isKeyExists = EXISTS rate.limiting:$IP
if $isKeyExists is
$times = INCR rate.limiting:$IP
if $times >
print 访问频率超过了限制,请稍后再试
exit
else
MULTI
INCR rate.limiting:$IP
EXPIRE $keyName,
EXEC

3. 排序
    (1) 有序集合的集合操作
    对于不常用到的或在不损失过多性能的前提下可使用现有命令实现的功能,Redis就不会单独提供命令来实现。
    (2) SORT命令
    SORT命令可以对列表、集合、有序集合进行排序,并完成与关系数据库中的连接查询相类似的任务。
    例:

# 对集合进行排序
127.0.0.1:> SADD tag:ruby:posts
(integer)
127.0.0.1:> SORT tag:ruby:posts
) ""
) ""
) ""
) ""
# 对列表进行排序
127.0.0.1:> lpush list
(integer)
127.0.0.1:> lrange list -
) ""
) ""
) ""
) ""
) ""
) ""
127.0.0.1:> sort list
) ""
) ""
) ""
) ""
) ""
) ""
# 对有序集合进行排序,会忽略元素的分数,只针对元素自身的值进行排序
127.0.0.1:> ZADD myzset
(integer)
127.0.0.1:> ZRANGE myzset - withscores
) ""
) ""
) ""
) ""
) ""
) ""
) ""
) ""
127.0.0.1:> SORT myzset
) ""
) ""
) ""
) ""

  SORT命令也可通过ALPHA参数实现按照字典顺序排列非数字元素:

127.0.0.1:> LPUSH mylistalpha a c e d B C A
(integer)
127.0.0.1:> SORT mylistalpha
(error) ERR One or more scores can't be converted into double
127.0.0.1:> SORT mylistalpha ALPHA
) "a"
) "A"
) "B"
) "c"
) "C"
) "d"
) "e"

  SORT命令的DESC参数可以实现将元素按照从大到小的顺序排列:

127.0.0.1:> SORT tag:ruby:posts DESC
) ""
) ""
) ""
) ""

  SORT命令还支持LIMIT参数返回指定范围的结果,格式为LIMIT offset count,表示跳过offset个元素并获取之后的count个元素。

127.0.0.1:> SORT tag:ruby:posts DESC LIMIT
) ""
) ""

  SORT对文章ID排序意义不大,如博客使用散列类型存储文章对象,time字段对应文章的发布时间,ID为2,6,12,26的四篇文章的time字段分别为1452619200,1452619600,1452620100,1452620000,如果按照文章的发布时间递减排序结果应为12,26,6,2,可通过SORT的BY参数可以实现。格式为:BY 参考键,其中参考键可为字符串类型键或散列类型键的某个字段(表示为键名->字段名)。SORT命令对每个元素使用元素的值替换参考键的第一个"*"并获取其值,然后依据该值对元素排序。

127.0.0.1:> HSET post: time
(integer)
127.0.0.1:> HSET post: time
(integer)
127.0.0.1:> HSET post: time
(integer)
127.0.0.1:> HSET post: time
(integer)
# 散列类型
127.0.0.1:> SORT tag:ruby:posts BY post:*->time DESC
) ""
) ""
) ""
) ""
#字符串类型
127.0.0.1:> LPUSH sortbylist
(integer)
127.0.0.1:> SET itemscore:
OK
127.0.0.1:> SET itemscore:
OK
127.0.0.1:> SET itemscore: -
OK
127.0.0.1:> LRANGE sortbylist -
) ""
) ""
) ""
127.0.0.1:> SORT sortbylist by itemscore:* DESC
) ""
) ""
) ""
# 当参考键名不包含"*"时,SORT命令将不会执行排序操作
127.0.0.1:> SORT sortbylist by anytext
) ""
) ""
) ""
# 如果几个元素的参考值相同,则SORT命令会再比较元素本身的值来决定元素的顺序
127.0.0.1:> SORT sortbylist BY itemscore:* DESC
) ""
) ""
) ""
) ""
# 当某个元素的值不存在时,会默认参考键的值为0
127.0.0.1:> SORT sortbylist BY itemscore:* DESC
) ""
) ""
) ""
) ""
) ""

注:参考键虽然支持散列类型,但是"*"只能在"->"符号前面(即键名部分)才有用,在"->"后(即字段名部分)会被当成字段名本身而不会作为占位符被元素的值替换,即常量键名,因此如下结果:

127.0.0.1:> SORT sortbylist BY itescore:->itemscore:*
) ""
) ""
) ""
) ""
) ""

  SORT的GET参数不影响排序,它的作用时使SORT命令返回结果不再是元素自身的值,而是GET参数中指定的键值,GET参数也支持字符串类型和散列类型的键,并使用"*"作为占位符。

127.0.0.1:> HSET post: title Java
(integer)
127.0.0.1:> HSET post: title MySQL
(integer)
127.0.0.1:> HSET post: title Redis
(integer)
127.0.0.1:> HSET post: title Hadoop
(integer)
127.0.0.1:> SORT tag:ruby:posts BY post:*->time DESC GET post:*->title
) "Redis"
) "Hadoop"
) "MySQL"
) "Java"
# SORT命令可以有多个GET参数,BY参数只能有一个
127.0.0.1:> SORT tag:ruby:posts BY post:*->time DESC GET post:*->title GET post:*->time
) "Redis"
) ""
) "Hadoop"
) ""
) "MySQL"
) ""
) "Java"
) ""
# "GET #"可以返回文章的ID,"GET #"会返回元素本身的值
127.0.0.1:> SORT tag:ruby:posts BY post:*->time DESC GET post:*->title GET post:*->time GET #
) "Redis"
) ""
) ""
) "Hadoop"
) ""
) ""
) "MySQL"
) ""
) ""
) "Java"
) ""
) ""

  SORT命令的STORE参数可以将排序结果保存起来,保存后的键的类型为list,返回值为list的个数:

127.0.0.1:> SORT tag:ruby:posts BY post:*->time DESC GET post:*->title GET post:*->time GET # STORE sort.result
(integer)
127.0.0.1:> TYPE sort.result
list
127.0.0.1:> LRANGE sort.result -
) "Redis"
) ""
) ""
) "Hadoop"
) ""
) ""
) "MySQL"
) ""
) ""
) "Java"
) ""
) ""

  STORE参数常用来结合EXPIRE命令缓存排序结果:

#判断是否存在之前排序结果的缓存
$isCacheExists = EXISTS cache.sort
if $isCacheExists is
# 若存在,直接返回
return LRANGE cache.sort -
else
# 若不存在,则使用SORT命令排序并将结果存入cache.sort键中作为缓存
$sortResult = SORT some.list STORE cache.sort
# 设置缓存的生存时间为10分钟
EXPIRE cache.sort
# 返回排序结果
return $sortResult

注:SORT命令的时间复杂度是O(n+mlogm),其中n表示要排序的列表中元素的个数,m表示要返回的元素个数,所以在开发中使用SORT命令需注意:1)尽可能减少待排序键中元素的数量;2)使用LIMIT参数只获取需要的数据;3)如果要排序的数据数量较大,尽可能使用STORE参数将结果缓存。

Redis学习笔记(4) Redis事务、生存时间及排序的更多相关文章

  1. redis学习笔记 - Pipeline与事务

    原文 Redis提供了5种数据结构,但除此之外,Redis还提供了注入慢查询分析,Redis Shell.Pipeline.事务.与Lua脚本.Bitmaps.HyperLogLog.PubSub.G ...

  2. Redis学习笔记(1) Redis介绍及基础

    1. Redis的特性 (1) 存储结构 Redis(Remote Dictionary Server,远程字典服务器)是以字典结构存储数据,并允许其他应用通过TCP协议读写字典中的内容.Redis支 ...

  3. redis学习笔记之redis简介

    redis简介 Redis是一个开源的,高性能的,基于键值对的缓存与存储系统,通过设置各种键值数据类型来适应不同场景下的缓存与存储需求.同事redis的诸多高层级功能使其可以胜任消息队列,任务队列等不 ...

  4. StackExchange.Redis学习笔记(一) Redis的使用初探

    Redis Redis将其数据库完全保存在内存中,仅使用磁盘进行持久化. 与其它键值数据存储相比,Redis有一组相对丰富的数据类型. Redis可以将数据复制到任意数量的从机中 Redis的安装 官 ...

  5. Redis学习笔记之Redis单机,伪集群,Sentinel主从复制的安装和配置

    0x00 Redis简介 Redis是一款开源的.高性能的键-值存储(key-value store).它常被称作是一款数据结构服务器(data structure server). Redis的键值 ...

  6. redis学习笔记(三)——redis的命令大全总结

    总结了一些redis五种存储类型的常用命令以及一些通用操作命令,不是很全,是在学习的时候将学到的做了个汇总,使用的时候可以查一下. 笔记写在表格里面了,不好粘贴.......后面的直接截图了..... ...

  7. Redis学习笔记之Redis中5种数据结构的使用场景介绍

    原来看过 redisbook 这本书,对 redis 的基本功能都已经熟悉了,从上周开始看 redis 的源码.目前目标是吃透 redis 的数据结构.我们都知道,在 redis 中一共有5种数据结构 ...

  8. Redis学习笔记(3) Redis基础类型及命令之二

    1. 集合类型 集合类型与列表类型有很多相似之处,但二者的区别在于:前者具有唯一性,但不具有有序性:后者具有有序性,但不具有唯一性.集合类型的常用操作是向集合中加入或删除元素.判断某个元素是否存在等, ...

  9. Redis学习笔记~StackExchange.Redis实现分布式Session

    回到目录 对于多WEB的环境现在已经是必须的了,很难想像一台WEB服务器面对百万并发的响应,所以,我们需要多台WEB服务器集群合作,来缓解这种高并发,高吞吐的场景,而对于多WEB的场景又会有个问题出现 ...

随机推荐

  1. AMD&CommonJS

    最近在学习nodejs的KOA框架,在查资料的时候遇见了点问题,顺着信息一步一步找下去,让我了解了一下一直以来不是很明白的什么时候用AMD规范,什么时候用CommonJS规范问题. CommonJS一 ...

  2. ThreadLocal

    package cn.happy.util; import org.hibernate.Session;import org.hibernate.SessionFactory;import org.h ...

  3. ios中蓝牙自动连接出现硬件提示框的问题

    出现如图所示情况,这时候有两种方法可以处理,一种是让硬件部修改硬件配对,另一种是程序里面测试该提示框的对应特征值,不要调用该特征值就不会出现 //2.扫描到Characteristics,特征回调 - ...

  4. Jquery 生成时钟

    $(function(){ showTime(); }): function showTime () { var curtime=new Date(); $(".getDateTime&qu ...

  5. 小三角图标如何用CSS写

    上三角▲     1 width: 0; 2 height: 0; 3 line-height: 0; 4 font-size: 0; 5 border-width: 10px; 6 border-s ...

  6. windows类书的学习心得(转载)

    原文网址:http://www.blogjava.net/sound/archive/2008/08/21/40499.html 现在的计算机图书发展的可真快,很久没去书店,昨日去了一下,真是感叹万千 ...

  7. Haxe数据类型

    以下是Haxe里面的一些数据类型 基本类型 空特性 类 枚举 匿名结构 方法 动态 抽象 1. 基本类型Bool, Float, Int 2. 空特性由于Haxe可以被编译为各种不同的target,不 ...

  8. Open vSwitch系列之二 安装指定版本ovs

    在ovs学习过程中,如果自己想要安装一个ovs交换机其实一条简单的命令 apt  install openvswitch 就可以了,但是这种方法只能安装低版本的ovs.在特殊情况下需要安装指定版本,例 ...

  9. JavaIO流——简单对文件的写入及读取(一)

    IO,即Input(输入)和Output(输出)的首字母缩写. 在编程语言的I/O类库中常使用流这个抽象概念.它代表任何有能力产出数据的数据源对象或者是与能力接收数据的接收端对象.“流”屏蔽了实际的I ...

  10. 关于C++ return * this

    转自 :https://blog.csdn.net/u011846436/article/details/45222905 不废话,直接上例子,使用赋值构造函数解释为什么需要 return *this ...