Redis客户端API操作 Jedis详解
redis是一个著名的key-value存储系统,也是nosql中的最常见的一种。其实,个人认为,redis最强大的地方不在于其存储,而在于其强大的缓存作用。
我们可以把它想象成一个巨大的(多借点集群,聚合多借点的内存)的Map,也就是Key-Value。
所以,我们可以把它做成缓存组件。
官方推荐的java版客户端是jedis,非常强大和稳定,支持事务、管道及有jedis自身实现。我们对redis数据的操作,都可以通过jedis来完成。
更多redis的概念,请参考:Redis集群(Redis3.0)
那我们就来看一看,jedis不同的调用方式:
(1)普通同步方式
这是一种最简单和最基础的调用方式,对于简单的数据存取需求,我们可以通过这种方式调用。
- public void jedisNormal() {
- Jedis jedis = new Jedis("localhost");
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- String result = jedis.set("n" + i, "n" + i);
- }
- long end = System.currentTimeMillis();
- System.out.println("Simple SET: " + ((end - start) / 1000.0) + " seconds");
- jedis.disconnect();
- }
- //每次set之后都可以返回结果,标记是否成功。
(2)事务方式(Transactions)
所谓事务,即一个连续操作,是否执行是一个事务,要么完成,要么失败,没有中间状态。
而redis的事务很简单,他主要目的是保障,一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令,也就是事务的连贯性。
- public void jedisTrans() {
- Jedis jedis = new Jedis("localhost");
- long start = System.currentTimeMillis();
- Transaction tx = jedis.multi();
- for (int i = 0; i < 100000; i++) {
- tx.set("t" + i, "t" + i);
- }
- List<Object> results = tx.exec();
- long end = System.currentTimeMillis();
- System.out.println("Transaction SET: " + ((end - start) / 1000.0) + " seconds");
- jedis.disconnect();
- }
- //我们调用jedis.watch(…)方法来监控key,如果调用后key值发生变化,则整个事务会执行失败。另外,事务中某个操作失败,并不会回滚其他操作。这一点需要注意。还有,我们可以使用discard()方法来取消事务。
(3)管道(Pipelining)
管道是一种两个进程之间单向通信的机制。
那再redis中,为何要使用管道呢?有时候,我们需要采用异步的方式,一次发送多个指令,并且,不同步等待其返回结果。这样可以取得非常好的执行效率。
- public void jedisPipelined() {
- Jedis jedis = new Jedis("localhost");
- Pipeline pipeline = jedis.pipelined();
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- pipeline.set("p" + i, "p" + i);
- }
- List<Object> results = pipeline.syncAndReturnAll();
- long end = System.currentTimeMillis();
- System.out.println("Pipelined SET: " + ((end - start) / 1000.0) + " seconds");
- jedis.disconnect();
- }
(4)管道中调用事务
对于,事务以及管道,这两个概念我们都清楚了。
在某种需求下,我们需要异步执行命令,但是,又希望多个命令是有连续的,所以,我们就采用管道加事务的调用方式。jedis是支持在管道中调用事务的。
- public void jedisCombPipelineTrans() {
- jedis = new Jedis("localhost");
- long start = System.currentTimeMillis();
- Pipeline pipeline = jedis.pipelined();
- pipeline.multi();
- for (int i = 0; i < 100000; i++) {
- pipeline.set("" + i, "" + i);
- }
- pipeline.exec();
- List<Object> results = pipeline.syncAndReturnAll();
- long end = System.currentTimeMillis();
- System.out.println("Pipelined transaction: " + ((end - start) / 1000.0) + " seconds");
- jedis.disconnect();
- }
- //效率上可能会有所欠缺
(5)分布式直连同步调用
这个是分布式直接连接,并且是同步调用,每步执行都返回执行结果。类似地,还有异步管道调用。
其实就是分片。
- public void jedisShardNormal() {
- List<JedisShardInfo> shards = Arrays.asList(
- new JedisShardInfo("localhost", 6379),
- new JedisShardInfo("localhost", 6380));
- ShardedJedis sharding = new ShardedJedis(shards);
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- String result = sharding.set("sn" + i, "n" + i);
- }
- long end = System.currentTimeMillis();
- System.out.println("Simple@Sharing SET: " + ((end - start) / 1000.0) + " seconds");
- sharding.disconnect();
- }
(6)分布式直连异步调用
- public void jedisShardpipelined() {
- List<JedisShardInfo> shards = Arrays.asList(
- new JedisShardInfo("localhost", 6379),
- new JedisShardInfo("localhost", 6380));
- ShardedJedis sharding = new ShardedJedis(shards);
- ShardedJedisPipeline pipeline = sharding.pipelined();
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- pipeline.set("sp" + i, "p" + i);
- }
- List<Object> results = pipeline.syncAndReturnAll();
- long end = System.currentTimeMillis();
- System.out.println("Pipelined@Sharing SET: " + ((end - start) / 1000.0) + " seconds");
- sharding.disconnect();
- }
(7)分布式连接池同步调用
如果,你的分布式调用代码是运行在线程中,那么上面两个直连调用方式就不合适了,因为直连方式是非线程安全的,这个时候,你就必须选择连接池调用。
连接池的调用方式,适合大规模的redis集群,并且多客户端的操作。
- public void jedisShardSimplePool() {
- List<JedisShardInfo> shards = Arrays.asList(
- new JedisShardInfo("localhost", 6379),
- new JedisShardInfo("localhost", 6380));
- ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);
- ShardedJedis one = pool.getResource();
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- String result = one.set("spn" + i, "n" + i);
- }
- long end = System.currentTimeMillis();
- pool.returnResource(one);
- System.out.println("Simple@Pool SET: " + ((end - start) / 1000.0) + " seconds");
- pool.destroy();
- }
(8)分布式连接池异步调用
- public void jedisShardPipelinedPool() {
- List<JedisShardInfo> shards = Arrays.asList(
- new JedisShardInfo("localhost", 6379),
- new JedisShardInfo("localhost", 6380));
- ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);
- ShardedJedis one = pool.getResource();
- ShardedJedisPipeline pipeline = one.pipelined();
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- pipeline.set("sppn" + i, "n" + i);
- }
- List<Object> results = pipeline.syncAndReturnAll();
- long end = System.currentTimeMillis();
- pool.returnResource(one);
- System.out.println("Pipelined@Pool SET: " + ((end - start) / 1000.0) + " seconds");
- pool.destroy();
- }
(9)需要注意的地方
事务和管道都是异步模式。在事务和管道中不能同步查询结果。比如下面两个调用,都是不允许的:
- Transaction tx = jedis.multi();
- for (int i = 0; i < 100000; i++) {
- tx.set("t" + i, "t" + i);
- }
- System.out.println(tx.get("t1000").get()); //不允许
- List<Object> results = tx.exec();
- …
- …
- Pipeline pipeline = jedis.pipelined();
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- pipeline.set("p" + i, "p" + i);
- }
- System.out.println(pipeline.get("p1000").get()); //不允许
- List<Object> results = pipeline.syncAndReturnAll();
事务和管道都是异步的,个人感觉,在管道中再进行事务调用,没有必要,不如直接进行事务模式。
分布式中,连接池的性能比直连的性能略好(见后续测试部分)。
分布式调用中不支持事务。
因为事务是在服务器端实现,而在分布式中,每批次的调用对象都可能访问不同的机器,所以,没法进行事务。
(10)总结
分布式中,连接池方式调用不但线程安全外,根据上面的测试数据,也可以看出连接池比直连的效率更好。
经测试分布式中用到的机器越多,调用会越慢。
(11)完整的测试代码
- package com.blogchong.example.nosqlclient;
- import java.util.Arrays;
- import java.util.List;
- import org.junit.AfterClass;
- import org.junit.BeforeClass;
- import org.junit.Test;
- import redis.clients.jedis.Jedis;
- import redis.clients.jedis.JedisPoolConfig;
- import redis.clients.jedis.JedisShardInfo;
- import redis.clients.jedis.Pipeline;
- import redis.clients.jedis.ShardedJedis;
- import redis.clients.jedis.ShardedJedisPipeline;
- import redis.clients.jedis.ShardedJedisPool;
- import redis.clients.jedis.Transaction;
- import org.junit.FixMethodOrder;
- import org.junit.runners.MethodSorters;
- /**
- * @Description: jedis的8种调用方式
- */
- @FixMethodOrder(MethodSorters.NAME_ASCENDING)
- public class TestJedis {
- private static Jedis jedis;
- private static ShardedJedis sharding;
- private static ShardedJedisPool pool;
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- List<JedisShardInfo> shards = Arrays.asList(
- new JedisShardInfo("localhost", 6379),
- new JedisShardInfo("localhost", 6379)); //使用相同的ip:port,仅作测试
- jedis = new Jedis("localhost");
- sharding = new ShardedJedis(shards);
- pool = new ShardedJedisPool(new JedisPoolConfig(), shards);
- }
- @AfterClass
- public static void tearDownAfterClass() throws Exception {
- jedis.disconnect();
- sharding.disconnect();
- pool.destroy();
- }
- @Test
- public void jedisNormal() {
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- String result = jedis.set("n" + i, "n" + i);
- }
- long end = System.currentTimeMillis();
- System.out.println("Simple SET: " + ((end - start) / 1000.0) + " seconds");
- }
- @Test
- public void jedisTrans() {
- long start = System.currentTimeMillis();
- Transaction tx = jedis.multi();
- for (int i = 0; i < 100000; i++) {
- tx.set("t" + i, "t" + i);
- }
- //System.out.println(tx.get("t1000").get());
- List<Object> results = tx.exec();
- long end = System.currentTimeMillis();
- System.out.println("Transaction SET: " + ((end - start) / 1000.0) + " seconds");
- }
- @Test
- public void jedisPipelined() {
- Pipeline pipeline = jedis.pipelined();
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- pipeline.set("p" + i, "p" + i);
- }
- //System.out.println(pipeline.get("p1000").get());
- List<Object> results = pipeline.syncAndReturnAll();
- long end = System.currentTimeMillis();
- System.out.println("Pipelined SET: " + ((end - start) / 1000.0) + " seconds");
- }
- @Test
- public void jedisCombPipelineTrans() {
- long start = System.currentTimeMillis();
- Pipeline pipeline = jedis.pipelined();
- pipeline.multi();
- for (int i = 0; i < 100000; i++) {
- pipeline.set("" + i, "" + i);
- }
- pipeline.exec();
- List<Object> results = pipeline.syncAndReturnAll();
- long end = System.currentTimeMillis();
- System.out.println("Pipelined transaction: " + ((end - start) / 1000.0) + " seconds");
- }
- @Test
- public void jedisShardNormal() {
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- String result = sharding.set("sn" + i, "n" + i);
- }
- long end = System.currentTimeMillis();
- System.out.println("Simple@Sharing SET: " + ((end - start) / 1000.0) + " seconds");
- }
- @Test
- public void jedisShardpipelined() {
- ShardedJedisPipeline pipeline = sharding.pipelined();
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- pipeline.set("sp" + i, "p" + i);
- }
- List<Object> results = pipeline.syncAndReturnAll();
- long end = System.currentTimeMillis();
- System.out.println("Pipelined@Sharing SET: " + ((end - start) / 1000.0) + " seconds");
- }
- @Test
- public void jedisShardSimplePool() {
- ShardedJedis one = pool.getResource();
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- String result = one.set("spn" + i, "n" + i);
- }
- long end = System.currentTimeMillis();
- pool.returnResource(one);
- System.out.println("Simple@Pool SET: " + ((end - start) / 1000.0) + " seconds");
- }
- @Test
- public void jedisShardPipelinedPool() {
- ShardedJedis one = pool.getResource();
- ShardedJedisPipeline pipeline = one.pipelined();
- long start = System.currentTimeMillis();
- for (int i = 0; i < 100000; i++) {
- pipeline.set("sppn" + i, "n" + i);
- }
- List<Object> results = pipeline.syncAndReturnAll();
- long end = System.currentTimeMillis();
- pool.returnResource(one);
- System.out.println("Pipelined@Pool SET: " + ((end - start) / 1000.0) + " seconds");
- }
- }
参考修改自:http://www.blogways.net/blog/2013/06/02/jedis-demo.html
Redis客户端API操作 Jedis详解的更多相关文章
- 深入浅出—Redis集群的相关详解
前言: 这篇文章主要介绍了Redis集群的相关,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值. 注意!要求使用的都是redis3.0以上的版本,因为3.0以上增加了red ...
- net平台下c#操作ElasticSearch详解
net平台下c#操作ElasticSearch详解 ElasticSearch系列学习 ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense Elasti ...
- Linux中redis安装配置及使用详解
Linux中redis安装配置及使用详解 一. Redis基本知识 1.Redis 的数据类型 字符串 , 列表 (lists) , 集合 (sets) , 有序集合 (sorts sets) , 哈 ...
- ElasticSearch-.net平台下c#操作ElasticSearch详解
ElasticSearch系列学习 ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense ElasticSearch第三步-中文分词 ElasticSea ...
- 【python】redis基本命令和基本用法详解
[python]redis基本命令和基本用法详解 来自http://www.cnblogs.com/wangtp/p/5636872.html 1.redis连接 redis-py提供两个类Redis ...
- c#操作ElasticSearch5详解
c#操作ElasticSearch详解 ElasticSearch系列学习 ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense ElasticSearc ...
- ElasticSearch第五步-.net平台下c#操作ElasticSearch详解
前面我们讲解了关于ElasticSearch的安装配置,以及CRUD 本章我将讲解怎么使用c#操作ElasticSearch. 首先你需要一定的技术储备,比如:asp.net webapi,mvc,j ...
- ASP.NET 操作Cookie详解 增加,修改,删除
ASP.NET 操作Cookie详解 增加,修改,删除 Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密).定义于RFC2109.它 ...
- 在telnet下操作memcache详解(操作命令详解)
这篇文章主要介绍了在telnet下操作memcache详解,telnet下的memcache操作命令详解,需要的朋友可以参考下 在定位问题.测试等时候经常需要对memcache的数据进行一些操作,但是 ...
随机推荐
- Oracle索引——位图索引
1.语法create bitmap index index_name on 表名(字段);2.举个例子你就能明白了:如有表 test(id,name,address)数据(1,张三,大连)(2,李四, ...
- 利用servlet产生随机数,原理是获取Graphics对象进行绘图
public class ResonpeRandomImgDemo extends HttpServlet { int width=100; int height=30; public void do ...
- 学SpringMVC收藏
一个较完整的SpringMVC工程的配置 2014-01-22 17:17:25 标签:java spring springMVC 配置 springSecurity web.xml 原创作品,允许 ...
- JS实现等比例缩放图片
JS实现等比例缩放图片 2014-01-19 21:57 by 龙恩0707, 40 阅读, 0 评论, 收藏, 编辑 JS实现等比例缩放图片 有时候我们前端页面只有500×500像素的宽和高的布局, ...
- SQLSERVER误删Windows登录用户
SQLSERVER误删除了Windows登录用户验证方式使用Windows身份验证的解决方法 SQLSERVER误删Windows登录用户验证方式使用Windows身份验证的解决方法 今天看到这篇 ...
- C#中另辟蹊径解决JSON / XML互转的问题
C#中另辟蹊径解决JSON / XML互转的问题 最近在一个POC的项目中要用到JSON和XML的相互转换, 虽然我知道很多类库如JSON.NET具备这种功能, 但是我还是另辟蹊径的使用Spider ...
- ASP.NET服务器端事件利用MARQUEE实现正在处理效果
前言:ASP.NET同仁们应该都遇到过当触发一个比较耗时的服务器端事件时,页面会处在一个等待的状态(即假死状态),用户体验非常不好,很容易造成用户二次点击,造成重复提交.至于解决方案自然是有的(问go ...
- linq to NHibernate
什么是linq to NHibernate 什么是linq to NHibernate?说简单一点就是linq + NHibernate. linq语句是.Net 3.5中新增的功能,从问世以来就 ...
- ssdt_hook NtOpenProcess
获取ssdt表中所有函数的地址 for (int i = 0; i < KeServiceDescriptorTable->NumberOfServices; i++) { ...
- 搜索广告与广告网络Demand技术-搜索广告
搜索广告 搜索广告就是一个典型的Ad Network,但是搜索广告非常重要,它的收入非常高,所以它有其独特之处,复杂度也比展示广告要高.它与展示广告在点击率预测,检索部分差不多,它的特点:1. 用户定 ...