jedis操作redis的几种常见方式总结

前言

Redis是一个著名的key-value存储系统,也是nosql中的最常见的一种。其实,个人认为,redis最强大的地方不在于其存储,而在于其强大的缓存作用。

我们可以把它想象成一个巨大的(多借点集群,聚合多借点的内存)的Map,也就是Key-Value。

所以,我们可以把它做成缓存组件。

官方推荐的Java版客户端是jedis,非常强大和稳定,支持事务、管道及有jedis自身实现。我们对redis数据的操作,都可以通过jedis来完成。

那我们就来看一看,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(); 

事务和管道都是异步的,个人感觉,在管道中再进行事务调用,没有必要,不如直接进行事务模式。

分布式中,连接池的性能比直连的性能略好(见后续测试部分)。

分布式调用中不支持事务。

因为事务是在服务器端实现,而在分布式中,每批次的调用对象都可能访问不同的机器,所以,没法进行事务。

总结

分布式中,连接池方式调用不但线程安全外,根据上面的测试数据,也可以看出连接池比直连的效率更好。

经测试分布式中用到的机器越多,调用会越慢。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Java客户端利用Jedis操作redis缓存示例代码

    前言 Redis是一个开源的Key-Value数据缓存,和Memcached类似.Redis多种类型的value,包括string(字符串).list(链表).set(集合).zset(sorted set --有序集合)和hash(哈希类型). Jedis 是 Redis 官方首选的 Java 客户端开发包.下面就来给大家详细关于Java客户端利用Jedis操作redis缓存的相关内容,话不多说,直接来看示例代码吧. 示例代码: //连接redis ,redis的默认端口是6379 Jedis

  • Java中使用Jedis操作Redis的示例代码

    使用Java操作Redis需要jedis-2.1.0.jar,下载地址:jedis-2.1.0.jar 如果需要使用Redis连接池的话,还需commons-pool-1.5.4.jar,下载地址:commons-pool-1.5.4.jar package com.test; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.j

  • java客户端Jedis操作Redis Sentinel 连接池的实现方法

    pom.xml配置 <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.0.2.RELEASE</version> </dependency> <dependency> <groupId>redis.clients<

  • Java中使用Jedis操作Redis的实现代码

    一.   redis的安装 1.下载源码,解压缩后编译源码. [root@cwt123 ~]# tar xzf redis-2.8.3.tar.gz [root@cwt123 ~]# cd redis-2.8.3 [root@cwt123 ~]# make 2.启动Redis服务.(src在redis-2.8.3下) [root@cwt123 ~]# cd src [root@cwt123 ~] ./redis-server 3.连接redis客户端 [root@cwt123 ~]# ./red

  • Redis 订阅发布_Jedis实现方法

    我想到使用Redis的订阅发布模式是用来解决推送问题的-. 对于概念性的叙述,多多少少还是要提一下的: 什么是Redis发布订阅?Redis发布订阅是一种消息通信模式,发送者通过通道A发送消息message,订阅过通道A的客户端就可以接收到消息message.嗯度娘上面的解释要比我所说的好多了,而我所理解的就是:所谓的订阅发布模式,其实和我们看电视,听广播差不多,在我们没有调台(换频道)的时候,那个频道也是在传递消息的(发布).我们换到那个频道上(订阅)就能接收到消息了.是的,虽然可能有些不恰当

  • 【Redis缓存机制】详解Java连接Redis_Jedis_事务

    Jedis事务 我们使用JDBC连接Mysql的时候,每次执行sql语句之前,都需要开启事务:在MyBatis中,也需要使用openSession()来获取session事务对象,来进行sql执行.查询等操作.当我们对数据库的操作结束的时候,是事务对象负责关闭数据库连接. 事务对象用于管理.执行各种数据库操作的动作.它能够开启和关闭数据库连接,执行sql语句,回滚错误的操作. 我们的Redis也有事务管理对象,其位于redis.clients.jedis.Transaction下. Jedis事

  • jedis操作redis的几种常见方式总结

    前言 Redis是一个著名的key-value存储系统,也是nosql中的最常见的一种.其实,个人认为,redis最强大的地方不在于其存储,而在于其强大的缓存作用. 我们可以把它想象成一个巨大的(多借点集群,聚合多借点的内存)的Map,也就是Key-Value. 所以,我们可以把它做成缓存组件. 官方推荐的Java版客户端是jedis,非常强大和稳定,支持事务.管道及有jedis自身实现.我们对redis数据的操作,都可以通过jedis来完成. 那我们就来看一看,jedis不同的调用方式: (1

  • Jedis操作Redis数据库的方法

    本文实例为大家分享了Jedis操作Redis数据库的具体代码,供大家参考,具体内容如下 关于NoSQL的介绍不写了,直接上代码 第一步导包,不多讲 基本操作: package demo; import org.junit.Test; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class Demo

  • 详解SpringBoot使用RedisTemplate操作Redis的5种数据类型

    目录 1.字符串(String) 1.1 void set(K key, V value):V get(Object key) 1.2 void set(K key, V value, long timeout, TimeUnit unit) 1.3 V getAndSet(K key, V value) 1.4 Integer append(K key, V value) 1.5 Long size(K key) 2.列表(List) 2.1 Long leftPushAll(K key, V

  • Java实现Map集合遍历的四种常见方式与用法分析

    本文实例讲述了Java实现Map集合遍历的四种常见方式与用法.分享给大家供大家参考,具体如下: ~Map集合是键值对形式存储值的,所以遍历Map集合无非就是获取键和值,根据实际需求,进行获取键和值 1. 无非就是通过map.keySet()获取到值,然后根据键获取到值 for(String s:map.keySet()){ System.out.println("key : "+s+" value : "+map.get(s)); } 2. 通过Map.Entry(

  • PHP数组遍历的几种常见方式总结

    本文实例讲述了PHP数组遍历的几种常见方式.分享给大家供大家参考,具体如下: 1.使用for循环遍历数组 conut($arr);用于统计数组元素的个数. for循环只能用于遍历,纯索引数组!!!! 如果存在关联数组,count统计时会统计两种数组的总个数,使用for循环遍历混合数组,导致数组越界!! eg: $arr = array(1,2,3,5,6,7); $num = count($arr); //count最好放到for外面,可以让函数只执行一次 echo "数组元素的个数{$num}

  • php使用redis的几种常见操作方式和用法示例

    本文实例讲述了php使用redis的几种常见操作方式和用法.分享给大家供大家参考,具体如下: 一.简单的字符串缓存 比如针对一些sql查询较慢,更新不频繁的数据进行缓存. <?php $redis = new Redis(); $redis->connect('127.0.0.1', 6379, 60); $sql = 'select * from tb_order order by id desc limit 10'; //伪代码,从数据库中获取数据 $data = $db->quer

  • c#操作Redis的5种基本类型汇总

    前言 在我们的项目中,通常会把数据存储到关系型数据库中,比如Oracle,SQL Server,Mysql等,但是关系型数据库对于并发的支持并不是很强大,这样就会造成系统的性能不佳,而且存储的数据多为结构化数据,对于非结构数据(比如文本)和半结构化数据(比如JSon) 就显得不够灵活,而非关系型数据库则很好的弥补了这两点, 我们通常把读操作频繁的数据写入Redis中,以Key-value的方式存储来提高性能. Redis支持5种数据类型:string(字符串),hash(哈希),list(列表)

  • Jedis操作Redis实现模拟验证码发送功能

    目录 jedis的创建 1.先启动redis 如果报 2.创建一个maven工程 3.创建一个class jedis实现模拟验证码 相关数据类型测试 Key String List set hash zset jedis的创建 1.先启动redis 如果报 那么说明你redis服务器服务器端还没打开 //启动服务端 redis-server /etc/redis.conf //启动客户端 redis-cli 如果启动成功,就是这样 2.创建一个maven工程 导入Jedis依赖 <depende

  • 详解Java创建线程的五种常见方式

    目录 Java中如何创建线程呢? 1.显示继承Thread,重写run来指定现成的执行代码. 2.匿名内部类继承Thread,重写run来执行线程执行的代码. 3.显示实现Runnable接口,重写run方法. 4.匿名内部类实现Runnable接口,重写run方法 5.通过lambda表达式来描述线程执行的代码 [面试题]:Thread的run和start之间的区别? Thread类的具体用法 Thread类常见的一些属性 中断一个线程 1.方法一:让线程run完 2.方法二:调用interr

  • 一文详解Python中实现单例模式的几种常见方式

    目录 Python 中实现单例模式的几种常见方式 元类(Metaclass): 装饰器(Decorator): 模块(Module): new 方法: Python 中实现单例模式的几种常见方式 元类(Metaclass): class SingletonType(type): """ 单例元类.用于将普通类转换为单例类. """ _instances = {} # 存储单例实例的字典 def __call__(cls, *args, **kwa

随机推荐