一、事务

  Redis中的事务是一组命令的集合。一个事务中的命令要么都执行,要么都不执行。

  1、事务简介

  事务的原理是先将一个事务的命令发送给Redis,然后再让Redis依次执行这些命令。下面看一个示例:

  

  首先,使用multi命令告诉Redis:下面我给你的命令属于同一个事务,你先不要执行,而是暂时存起来。

  然后,我们发送两个set命令来实现赋值,可以看到redis没有执行这些命令,而是返回queued表示这两条命令已经进入等待执行的事务队列中。

  当所有要在同一事务中执行的命令都发给Redis后,用exec命令告诉Redis将等待执行的事务队列中所有的命令按照发送顺序依次执行。

  2、错误处理

  当一个事务中某个命令执行出错时,Redis会怎样处理呢?这里有二种情况:

  情况一:语法错误,指错命令不存在或者命令参数的个数不对

  

  可以看到,跟在multi命令后执行了三个命令,第二个和第三个命令有语法错误,执行exec后redis就会执行返回错误。

  情况二:运行错误,指在命令执行时出现的错误。

  

  这种错误在实际执行前redis是无法发现的,所以在事务里这样的命令是会被redis接受和执行的,如果事务里一条命令出现了运行错误,事务里其他的命令依然会继续执行(包括出错命令之后的命令)。

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

  3、Watch命令

  watch命令可以监控一个或多个键,一旦其中一个键被修改或删除,之后的事务就不会执行,监控一直持续到exec命令(但是不能保证其他客户不修改这一键值)。

  

  上例中执行watch命令后,事务执行前修改了key值,所以事务中命令set username xujian没有执行,exec命令返回空结果。

  注意:执行exec命令后立即取消对所有键的监控,如果不想执行事务中的命令也可以使用unwatch命令来保证下一个事务的执行不会受到影响。

二、生存时间

  在Redis中,可以使用expire命令设置一个键的生存时间,到时间后Redis会自动删除它。

  expire命令的使用方法为expire key seconds,其中seconds参数表示键的生存时间,单位是秒。如果想知道一个键还有多久的时间会被删除,可以使用TTL命令,返回值是键的剩余时间(单位是秒)。如果想取消键的生存时间设置,即将恢复永久的,可以使用persist命令。

  

三、排序

  1、有序集合

  有序集合常见的使用场景是大数据排序,如游戏的玩家排行榜。

  2、sort命令

  sort命令可以对列表类型、集合类型和有序集合类型键进行排序,并且可以完成与关系数据库中的连接查询相类似的任务。

  对List进行排序:

  

  对有序集合类型排序时会忽略元素的分数,只针对元素自身的值进行排序:

  

3、by参数

  by参数的语法为“by 参考键”,其中参考键可以是字符串类型键或者是散列类型键的某个字段。如果提供了by参数,sort命令将不再依据元素自身的值进行排序,而是对每个元素使用元素的值替换参考键中的第一个“*”并获取其值,然后依据该值对元素排序:

  

4、store参数

  默认情况下,sort会直接返回排序结果,如果希望保存排序结果,可以使用store参数。

  注意:sort命令的时间复杂度是O(n+mlogm),其中n表示要排序的列表(集合或有序集合)中的元素个数,m表示要返回的元素的个数。当n较大的时候sort命令的性能相对较低,并且redis在排序前会建立一个长度为n的容器来存储待排序的元素。在开发中使用sort要注意以下几点:

  1、尽可能减少待排序键中元素的数量(使n尽可能小)

  2、使用limit参数只获取需要的数据(使m尽可能小)

  3、如果要排序的数据量较大,尽可能使用store参数将结果缓存

四、消息通知

  一般来说,消息队列有两种场景,一种是生产者消费者模式,一种是发布者订阅者模式。利用redis这两种场景的消息队列都能实现。

  1、生产者消费者模式

  生产者生产消息放到队列中,多个消费者同时监听队列,谁先抢到消息谁就会从队列中取走消息,即对于每个消息最多只能被一个消费者拥有。

  具体的方法就是创建一个任务队列,生产者主动lpush消息,而消费者去rpop数据。但是这样存在一个问题,就是消费者需要主动去请求数据,周期性的请求会造成资源的浪费。如果可以实现一旦有新消息加入队列就通知消费者就好了,这时借助brpop命令就可以实现这样的需求。brpop和rpop命令相似,唯一区别就是当列表中没有元素时,brpop命令会一直阻塞住连接,直到有新元素加入。

BRPOP key timeout

  brpop命令接收两个参数,第一个参数key为键值,第二个参数timeout为超时时间。BRPOP命令取数据时候,如果暂时不存在数据,该命令会一直阻塞直到达到超时时间。如果timeout设置为0,那么就会无限等待下去。

  

  2、发布者订阅者模式

  发布者生产消息放到队列里,多个监听队列的订阅者都会受到同一份消息。

  生产者使用下面命令来发布消息:

PUBLISH CHANNEL MESSAGE

  订阅者通过下面的命令来订阅消息,执行subscribe命令后,客户端进入订阅状态,处于此状态的客户端不能使用4个属于“发布/订阅”模型的命令之外的命令。另外,可以使用subscribe channel1.1 channel1.2 ... 同时订阅多个频道。

SUBSCRIBE CHANNEL

  

  3、Java实现的redis的消息队列

  在jedis中,有对应的方法进行订阅和发布,为了传输对象,需要将对象进行序列化,并封装成字符串进行处理。

  下面我们要实现三个类,一个对应publish,一个对应subscribe,一个对应要传递的对象实体类:

  实体类:

import java.io.Serializable;
/**
* 实体类
* 封装消息
* @author Administrator
*
*/
public class Message implements Serializable
{
private static final long serialVersionUID = 1L;
private String title;
private String content;
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getContent()
{
return content;
}
public void setContent(String content)
{
this.content = content;
}
}

  Publish类:

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import redis.clients.jedis.Jedis;
/**
* 发布者,用于发布消息
* @author Administrator
*
*/
public class TestPub
{
public static void main(String[] args)
{
Jedis jedis = new Jedis("127.0.0.1");
try
{
Message message = new Message();
message.setTitle("体育新闻");
message.setContent("著名NBA球星科比退役了!");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(message);
String msg1 = baos.toString("ISO-8859-1"); jedis.publish("foo", msg1);
} catch (Exception e)
{
e.printStackTrace();
}
jedis.close();
}
}

  Subscribe类:

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
/**
* 订阅者,用于接收消息
* @author Administrator
*
*/
public class TestSub
{
public static void main(String[] args)
{
Jedis jedis = new Jedis("127.0.0.1");
JedisPubSub jedisPubSub = new JedisPubSub()
{
@Override
public void onUnsubscribe(String channel, int subscribedChannels)
{
} @Override
public void onSubscribe(String channel, int subscribedChannels)
{
} @Override
public void onPUnsubscribe(String pattern, int subscribedChannels)
{
} @Override
public void onPSubscribe(String pattern, int subscribedChannels)
{
} @Override
public void onPMessage(String pattern, String channel, String message)
{
} @Override
public void onMessage(String channel, String message)
{
try
{
ByteArrayInputStream bis = new ByteArrayInputStream(message.getBytes("ISO-8859-1"));
            // 此处指定字符集将字符串编码成字节数组,此处的字符集需要与发布时的字符集保持一致
ObjectInputStream ois = new ObjectInputStream(bis);
Message message2= (Message) ois.readObject();
System.out.println(message2.getTitle()+"\n"+message2.getContent());
} catch (Exception e)
{
e.printStackTrace();
} finally
{ }
}
};
jedis.subscribe(jedisPubSub, "foo");
jedis.close();
}
}

  先执行订阅操作,然后发布者发布消息,执行结果为:

  

五、管道

  客户端和Redis使用TCP协议连接,不管是客户端向Redis发送命令还是Redis向客户端返回命令的执行结果,都需要经过网络传输。在执行过个命令时,每条命令都需要等待上一条命令执行完才能执行,即使命令不需要上一条命令的执行结果。

  Redis的底层通信协议对管道提供了支持,通过管道可以一次性发送多条命令并在执行完后一次性将结果返回,当一组命令中每条命令都不依赖之前命令的执行结果时就可以将这组命令一起通过管道发出。管道通过减少客户端与Redis的通信次数来实现降低往返时延累计值的目的。

六、存储优化

  1、精简键名和键值

  2、内部编码优化

七、参考资料

  1、Redis入门指南

Redis系列二之事务及消息通知的更多相关文章

  1. Redis系列(二):Redis的数据类型及命令操作

    原文链接(转载请注明出处):Redis系列(二):Redis的数据类型及命令操作 Redis 中常用命令 Redis 官方的文档是英文版的,当然网上也有大量的中文翻译版,例如:Redis 命令参考.这 ...

  2. Redis自学笔记:4.4进阶-消息通知

    4.4消息通知 4.4.1任务队列 传递任务的队列.与任务队列进行交互的实体有两类,一类是生产者,一类是消费者. 生产者将需要处理的任务放入任务队列中,二消费者不断从任务队列中读入任务 信息并执行. ...

  3. RabbitMQ学习系列二-C#代码发送消息

    RabbitMQ学习系列二:.net 环境下 C#代码使用 RabbitMQ 消息队列 http://www.80iter.com/blog/1437455520862503 上一篇已经讲了Rabbi ...

  4. Redis系列(二):Redis的5种数据结构及其常用命令

    上一篇博客,我们讲解了什么是Redis以及在Windows和Linux环境下安装Redis的方法, 没看过的同学可以点击以下链接查看: Redis系列(一):Redis简介及环境安装. 本篇博客我们来 ...

  5. Redis系列二:reids介绍

    一.什么是redis.redis有哪些特性.redis有哪些应用场景.redis的版本 1. 什么是redis redis是一种基于键值对(key-value)数据库,其中value可以为string ...

  6. Redis系列(二)-Hredis客户端设计及开源

    接上篇c#实现redis客户端(一),重新整理些了下. 阅读目录: 项目说明 Hredis设计图 单元测试场景 总结 项目说明 背景:因为有地方要用,而又没找到对sentinel良好支持的Net客户端 ...

  7. redis系列二: linux下安装redis

    下面介绍在Linux环境下,Redis的安装与配置 一. 安装 1.首先上官网下载Redis 压缩包,地址:http://redis.io/download 下载稳定版3.0即可. 2.通过远程管理工 ...

  8. Redis系列二 - 数据结构

    前言 redis作为我们开发的一大神器,我们接触肯定不会少,但是很多同学也许只会存储String类型的值,这是非常不合理的.在这里,将带大家认识Redis的5中数据结构. 1.问:Redis有那些数据 ...

  9. Redis系列(五):消息队列

    消息队列已经成为现在互联网服务端的标配组件,现在比较常用的消息中间件有RabbitMQ.Kafka.RocketMQ.ActiveMQ.说出来你可能不信,Redis作为一个缓存中间件,居然也提供了消息 ...

随机推荐

  1. Senparc.Weixin.MP SDK 微信公众平台开发教程(十四):请求消息去重

    为了确保信息请求消息的到达率,微信服务器在没有及时收到响应消息(ResponseMessage)的情况下,会多次发送同一条请求消息(RequestMessage),包括MsgId等在内的所有文本内容都 ...

  2. IOS Animation-CABasicAnimation、CAKeyframeAnimation详解&区别&联系

    1.先看看网上流传的他们的继承图: 从上面可以看出CABasicAnimation与CAKeyframeAnimation都继承于CAPropertyAnimation.而CAPropertyAnim ...

  3. NodeJS系列~第四个小例子,NodeJs处理Get请求和Post请求

    返回目录 说在前 对于HTTP请求来说,我们通常使用的是Get和Post,除此之外还有put,delete等,而对于get来说,比较lightweight,只是对字符串的传输,它会被添加到URL地址里 ...

  4. Oracle VM VirtualBox配置文件

    Linux 虚拟机配置文件分为两处. windows下: 1.用户名/.VirtualBox/ 这里面有2个配置文件: VirtualBox.xml 和 VirtualBox.xml-prev. 后面 ...

  5. JS中的宽高(基础知识很重要)

    IE中:document.body.clientWidth ==> BODY对象宽度document.body.clientHeight ==> BODY对象高度document.docu ...

  6. CefSharp .net

    构建基于Chromium的应用程序 chromium是google chrome浏览器所采用的内核,最开始由苹果的webkit发展而出,由于webkit在发展上存在分歧,而google希望在开发上有更 ...

  7. iOS-性能优化2

    性能优化总结2 iOS应用是非常注重用户体验的,不光是要求界面设计合理美观,也要求各种UI的反应灵敏,我相信大家对那种一拖就卡卡卡的 TableView 应用没什么好印象.还记得12306么,那个速度 ...

  8. IOS笔记045-UIDatePicker和UIPickerView

    这是两种可以上下滚动的控件. 这是UIDatePicker,可以显示日期和时间. 这个是UIPickerView,显示类似几个选择项的界面. 注意点:PickerView的高度不能改,默认162,Pi ...

  9. java 线程安全 Lock

    java.util.concurrent.locks 对于线程安全我们前面使用了synchronized关键字,对于线程的协作我们使用Object.wait()和Object.notify().在JD ...

  10. js 数组

    js中的数组类似与java中的容器 类型可以不同.长度可变 一.数组的声明 var arr1=new Array();//数组的声明一     var arr2=[1,2,3,true,new Dat ...