【redis】——jedis简单了解和使用

        使用Jedis提供的Java API对Redis进行操作,是Redis官方推崇的方式;并且使用Jedis提供的对Redis的支持是最为灵活全面的;

        首先需要在项目中添加对jedis的jar包。在使用时单机版和集群版有区别,分别看一下在项目中的使用。

单机版

        创建单实例jedis对象连接redis服务

// 单实例连接redis
    @Test
    public voidtestJedisSingle() {
 
       Jedis jedis = new Jedis("192.168.190.3", 6379);//实例化一个jedis
       jedis.set("name", "zhangsan");//存储
       String name = jedis.get("name");//获取
       System.out.println(name);//输出
 
    }


        单实例连接redis不能对redis连接进行共享,可以使用连接池对redis连接进行共享,提高资源利用率。

@Test
    public void testPool() {
       JedisPoolConfig config = newJedisPoolConfig();
       //最大连接数
       config.setMaxTotal(10);
       //最大连接空闲数
       config.setMaxIdle(2);
      
       JedisPool pool = newJedisPool(config, "192.168.190.3", 6379);//创建连接池
       Jedis jedis = null;
 
       try  {
           jedis =pool.getResource();//通过连接池获取redis实例
          
           jedis.set("name", "zhangsan");//赋值
           String name = jedis.get("name");//取值
           System.out.println(name);
       }catch(Exception ex){
           ex.printStackTrace();
       }finally{
           if(jedis != null){
              //关闭连接
              jedis.close();
           }
       }
      
    }


集群版

        使用连接池

// 连接redis集群
    @Test
    public voidtestJedisCluster() {
 
       JedisPoolConfig config = newJedisPoolConfig();
       // 最大连接数
       config.setMaxTotal(10);
       // 最大连接空闲数
       config.setMaxIdle(2);
 
       //集群结点
       Set<HostAndPort>jedisClusterNode = new HashSet<HostAndPort>();
       jedisClusterNode.add(new HostAndPort("192.168.190.3", 7001));
       jedisClusterNode.add(new HostAndPort("192.168. 190.3", 7002));
       jedisClusterNode.add(new HostAndPort("192.168. 190.3", 7003));
       jedisClusterNode.add(new HostAndPort("192.168. 190.3", 7004));
       jedisClusterNode.add(new HostAndPort("192.168. 190.3", 7005));
       jedisClusterNode.add(new HostAndPort("192.168.190.3", 7006));
       JedisCluster jc = newJedisCluster(jedisClusterNode, config);
      
       JedisCluster jcd = newJedisCluster(jedisClusterNode);
       jcd.set("name", "zhangsan");
       String value = jcd.get("name");
       System.out.println(value);
    } 

 

        和spring整合:

                以上单机版和集群版都使用到了连接池,连接池的属性应该是灵活可配的可以和spring的配置文件进行整             合。可以独立建立一个applicationContext-jedis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
    <!-- 连接池配置 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
       <!-- 最大连接数 -->
       <property name="maxTotal" value="30" />
       <!-- 最大空闲连接数 -->
       <property name="maxIdle" value="10" />
       <!-- 每次释放连接的最大数目 -->
       <property name="numTestsPerEvictionRun" value="1024" />
       <!-- 释放连接的扫描间隔(毫秒) -->
       <property name="timeBetweenEvictionRunsMillis" value="30000" />
       <!-- 连接最小空闲时间 -->
       <property name="minEvictableIdleTimeMillis" value="1800000" />
       <!-- 连接空闲多久后释放, 当空闲时间>该值且空闲连接>最大空闲连接数时直接释放 -->
       <property name="softMinEvictableIdleTimeMillis" value="10000" />
       <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
       <property name="maxWaitMillis" value="1500" />
       <!-- 在获取连接的时候检查有效性, 默认false -->
       <property name="testOnBorrow" value="true" />
       <!-- 在空闲时检查有效性, 默认false -->
       <property name="testWhileIdle" value="true" />
       <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
       <property name="blockWhenExhausted" value="false" />
    </bean>   
    <!-- jedis客户端单机版 -->
    <!-- <bean id="redisClient" class="redis.clients.jedis.JedisPool">
       <constructor-arg name="host" value="192.168.25.153"></constructor-arg>
       <constructor-arg name="port" value="6379"></constructor-arg>
       <constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
    </bean>
    <bean id="jedisClient" class="com.taotao.rest.dao.impl.JedisClientSingle"/> -->
   
   
    <!-- jedis集群版配置 -->
    <bean id="redisClient" class="redis.clients.jedis.JedisCluster">
       <constructor-arg name="nodes">
           <set>
              <bean class="redis.clients.jedis.HostAndPort">
                  <constructor-arg name="host" value="192.168.25.153"></constructor-arg>
                  <constructor-arg name="port" value="7001"></constructor-arg>
              </bean>
              <bean class="redis.clients.jedis.HostAndPort">
                  <constructor-arg name="host" value="192.168.25.153"></constructor-arg>
                  <constructor-arg name="port" value="7002"></constructor-arg>
              </bean>
              <bean class="redis.clients.jedis.HostAndPort">
                  <constructor-arg name="host" value="192.168.25.153"></constructor-arg>
                  <constructor-arg name="port" value="7003"></constructor-arg>
              </bean>
              <bean class="redis.clients.jedis.HostAndPort">
                  <constructor-arg name="host" value="192.168.25.153"></constructor-arg>
                  <constructor-arg name="port" value="7004"></constructor-arg>
              </bean>
              <bean class="redis.clients.jedis.HostAndPort">
                  <constructor-arg name="host" value="192.168.25.153"></constructor-arg>
                  <constructor-arg name="port" value="7005"></constructor-arg>
              </bean>
              <bean class="redis.clients.jedis.HostAndPort">
                  <constructor-arg name="host" value="192.168.25.153"></constructor-arg>
                  <constructor-arg name="port" value="7006"></constructor-arg>
              </bean>
           </set>
       </constructor-arg>
       <constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
    </bean>
    <bean id="jedisClientCluster" class="com.taotao.rest.dao.impl.JedisClientCluster"></bean>
</beans>


        以上配置文件中添加了redis的连接池,同时配置了单机版和集群版的bean,当然单机版和集群版是不能同时存在的,分别测试好了以后在开放时可以使用单机版的,单机版redis可以使用可视化功能查看其中的数据,在发布时切换到集群版。

/**
     * 单机版测试
     * <p>Title: testSpringJedisSingle</p>
     * <p>Description: </p>
     */
    @Test
    public void testSpringJedisSingle() {
       ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
       JedisPool pool = (JedisPool) applicationContext.getBean("redisClient");
       Jedis jedis = pool.getResource();
       jedis.set("key0", "jedis test");
       String string = jedis.get("key0");
       System.out.println(string);
       jedis.close();
       pool.close();
    }
     /**
     * 集群版测试
     * <p>Title: testSpringJedisCluster</p>
     * <p>Description: </p>
     */
 
    @Test
    public void testSpringJedisCluster() {
       ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
       JedisCluster jedisCluster =  (JedisCluster) applicationContext.getBean("redisClient");
       cluster.set("key1", "1000");
       String string = jedisCluster.get("key1");
       System.out.println(string);
       jedisCluster.close();
    }

        

小结 

        实例中只使用了jedis的set方法,其他方法的使用可以查询redis的api。在实际的业务中使用时jedis的使用不能影响正常的业务逻辑。

Jedis使用总结 前段时间细节的了解Jedis使用Jedisredis的java版本的客户端实现。 本文做个总结,主要分享如下内容: 【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】 好了,一个一个来。 一、 Pipeline 官方的说明是:starts a pipeline,which is a very efficient way to send lots of command and read all the responses when you finish sending them。简单点说pipeline适用于批处理。当有大量的操作需要一次性执行的时候,可以用管道。 示例: Jedis jedis = new Jedis(String, int); Pipeline p = jedis.pipelined(); p.set(key,value);//每个操作都发送请求给redis-server p.get(key,value); p.sync();//这段代码获取所有的response 这里我进行了20w次连续操作(10w读,10w写),不用pipeline耗时:187242ms,用pipeline耗时:1188ms,可见使用管道后的性能上了一个台阶。看了代码了解到,管道通过一次性写入请求,然后一次性读取响应。也就是说jedis是:request response,request response,...;pipeline则是:request request... response response的方式。这样无需每次请求都等待server端的响应。 二、 跨jvm的id生成器 谈到这个话题,首先要知道redis-server端是单线程来处理client端的请求的。 这样来实现一个id生成器就非常简单了,只要简单的调用jdeis.incr(key);就搞定了。 你或许会问,incr是原子操作吗,能保证不会出现并发问题吗,不是说了吗,server端是单线程处理请求的。 三、 【跨jvm的锁实现【watch】【multi】】 首先说下这个问题的使用场景,有些时候我们业务逻辑是在不同的jvm进程甚至是不同的物理机上的jvm处理的。这样如何来实现不同jvm上的同步问题呢,其实我们可以基于redis来实现一个锁。 具体事务和监听请参考文章:redis学习笔记之事务 暂时找到三种实现方式: 1. 通过jedis.setnx(key,value)实现 import java.util.Random; import org.apache.commons.pool.impl.GenericObjectPool.Config; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.Transaction; /** * @author Teaey */ public class RedisLock { //加锁标志 public static final String LOCKED = "TRUE"; public static final long ONE_MILLI_NANOS = 1000000L; //默认超时时间(毫秒) public static final long DEFAULT_TIME_OUT = 3000; public static JedisPool pool; public static final Random r = new Random(); //锁的超时时间(秒),过期删除 public static final int EXPIRE = 5 * 60; static { pool = new JedisPool(new Config(), "host", 6379); } private Jedis jedis; private String key; //锁状态标志 private boolean locked = false; public RedisLock(String key) { this.key = key; this.jedis = pool.getResource(); } public boolean lock(long timeout) { long nano = System.nanoTime(); timeout *= ONE_MILLI_NANOS; try { while ((System.nanoTime() - nano) < timeout) { if (jedis.setnx(key, LOCKED) == 1) { jedis.expire(key, EXPIRE); locked = true; return locked; } // 短暂休眠,nano避免出现活锁 Thread.sleep(3, r.nextInt(500)); } } catch (Exception e) { } return false; } public boolean lock() { return lock(DEFAULT_TIME_OUT); } // 无论是否加锁成功,必须调用 public void unlock() { try { if (locked) jedis.del(key); } finally { pool.returnResource(jedis); } } } 2. 通过事务(multi)实现 由于采纳第一张方法,第二种跟第三种实现只贴了关键代码,望谅解。^_^ public boolean lock_2(long timeout) { long nano = System.nanoTime(); timeout *= ONE_MILLI_NANOS; try { while ((System.nanoTime() - nano) < timeout) { Transaction t = jedis.multi(); // 开启事务,当server端收到multi指令 // 会将该client的命令放入一个队列,然后依次执行,知道收到exec指令 t.getSet(key, LOCKED); t.expire(key, EXPIRE); String ret = (String) t.exec().get(0); if (ret == null || ret.equals("UNLOCK")) { return true; } // 短暂休眠,nano避免出现活锁 Thread.sleep(3, r.nextInt(500)); } } catch (Exception e) { } return false; } 3. 通过事务+监听实现 public boolean lock_3(long timeout) { long nano = System.nanoTime(); timeout *= ONE_MILLI_NANOS; try { while ((System.nanoTime() - nano) < timeout) { jedis.watch(key); // 开启watch之后,如果key的值被修改,则事务失败,exec方法返回null String value = jedis.get(key); if (value == null || value.equals("UNLOCK")) { Transaction t = jedis.multi(); t.setex(key, EXPIRE, LOCKED); if (t.exec() != null) { return true; } } jedis.unwatch(); // 短暂休眠,nano避免出现活锁 Thread.sleep(3, r.nextInt(500)); } } catch (Exception e) { } return false; } 最终采用第一种实现,因为加锁只需发送一个请求,效率最高。 四、 【redis分布式】 最后一个话题,jedis的分布式。在jedis的源码里发现了两种hash算法(MD5,MURMUR Hash(默认)),也可以自己实现redis.clients.util.Hashing接口扩展。 List hosts = new ArrayList(); //server1 JedisShardInfo host1 = new JedisShardInfo("", 6380, 2000); //server2 JedisShardInfo host2 = new JedisShardInfo("", 6381, 2000); hosts.add(host1); hosts.add(host2); ShardedJedis jedis = new ShardedJedis(hosts); jedis.set("key", "");
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值