• 欢迎访问 winrains 的个人网站!
  • 本网站主要从互联网整理和收集了与Java、网络安全、Linux等技术相关的文章,供学习和研究使用。如有侵权,请留言告知,谢谢!

Redis使用教程(4):Jedis

Redis winrains 来源:田守芝 11个月前 (10-20) 37次浏览

5 Jedis简介

在此之前我们进行的操作都是通过Redis的命令行客户端redis-cli进行的,并没有介绍实际编程时如何操作Redis。
本章将会介绍Java客户端的使用方法。

5.1.1 Jedis简介

Jedis其实可以理解为一个驱动,想一想我们在使用 java链接mysql 数据库的时候,是不是需要使用驱动: mysql-connector-java-5.1.2-bin.jar。
同样作为数据库,java链接Redis 也是需要需要驱动的,这个驱动就是 Jedis。
事实上,Redis对几十种编程语言客户端提供了支持。基本上,主流的编程语言都可以操作 redis。
在http://www.redis.cn/clients.html上可以查看redis对哪些编程语言提供了支持。以 java为例,有四种方式都可以去操作 redis.
Image.png
事实上,Redis对几十种编程语言客户端提供了支持。基本上,主流的编程语言都可以操作 redis。
官方建议是使用 Jedis,J 代表的就是Java。

5.1.2 下载安装Jedis

Maven用户:
在pom.xml文件中添加

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.6.0</version>
    <type>jar</type>
    <scope>compile</scope>
</dependency>

非Maven用户:
Jedis所有版本的下载地址为: https://github.com/xetorthio/jedis/releases
本文使用的是最新版本 V2.6.2
下载完成之后,进入 src\main\java,将里面的redis 文件夹拷贝到项目的 src目录下。此外你还要导入另外一个 jar, commons-pool2-2.0.jar ,Jedis需要依赖这个 jar才能编译成功。

5.1.3 HelloRedis

关于以下代码,暂时不用深究,只是为了测试开发环境是否搭建成功,后面的教程中会有详细的讲解。

package com.tianshouzhi;
import redis.clients.jedis.Jedis;
/**
 * HelloRedis : 第一个 Redis案例:向 Redis 中存储一个键值对,然后再查询出来并打印
 *
 * @author tianshouzhi
 *
 */
public class HelloRedis {
    public static void main(String[] args) {
        // Connecting to Redis server on localhost
        Jedis jedis = new Jedis("localhost");
        System.out.println("Connection to server sucessfully");
        // check whether server is running or not
        System.out.println("Server is running: " + jedis.ping());
    }
}

运行代码,如果你的控制台打印出来以下内容

Connection to server sucessfully
Server is running: PONG

恭喜你,你已经成功的进行了一次 java对redis 进行的操作。同时证明我们了我们的开发环境已经搭建好。
说明:Jedis对象是在 java中操作redis 最核心的类,当 new的时候,就与服务器建立了连接。在后面的代码中,我们将不会再重复这个 new的过程,只介绍其api如何使用。

5.1.4可能的异常

如果你出现了异常ConnectionTimeoutException,连接超时异常,那么可能是:
1、 因为你的ip地址输错,使用ifconfig可以查看你的linux的ip地址信息
2、 如果不是第一个原因,则可能是因为你的服务器防火墙没有针对6379端口开放,redis默认监听的就是这个端口,为了方便,可以选择直接关闭防火墙.命令为:service iptables stop
3、如果redis-server不是在6379端口启动,那么使用redis-cli连接的时候需要指定端口号。同理,这种情况下,使用java操作redis,也要指定端口等信息。

5.1.5Jedis设计

Jedis作为推荐的java语言redis客户端,其抽象封装为三部分:

  • 对象池设计:Pool,JedisPool,GenericObjectPool,BasePoolableObjectFactory,JedisFactory
  • 面向用户的redis操作封装:BinaryJedisCommands,JedisCommands,BinaryJedis,Jedis
  • 面向redis服务器的操作封装:Commands,Client,BinaryClient,Connection,Protocol

其类设计图如下:
cd3e4917-0dd5-3de9-9a7d-3781c2c246a6.jpg
关于common-pool的相关内容,可以参见:http://macrochen.iteye.com/blog/320077
其他类的设计作用如下:

类名 职责
Pool 抽象Jedis对象池操作;并委托给操作给GenericObjectPool
JedisPool 实现Pool并提供JedisFactory工厂
JedisFactory 实现BasePoolableObjectFactory,提供创建,销毁Jedis方法
BinaryJedisCommands 抽象面向客户端操作的Redis命令;key,value都为序列化后的byte数组
JedisCommands 抽象面向客户端操作的Redis命令;提供String类型的key,value
BinaryJedis 实现BinaryJedisCommands接口,并将实际操作委托给Client
Jedis 实现JedisCommands接口,并将操作委托给Client
Commands 抽象Redis操作接口,提供String类型的key,value操作;被Jedis调用
Connection 抽象了Redis连接;包括host,port,pass,socket,inputstream,outputstream,protocol 完成与Redis服务器的通信
Protocol 抽象了Redis协议处理
BinaryClient 继承Connection类,封装了基于Byte[]的key,value操作
Client 继承BinaryClient同时实现了Commands,对上层提供基于String类型的操作

参考:
http://yychao.iteye.com/blog/1751583

5.1 Jedis基本使用

本节讲解如何通过Jedis来操作Redis中的各种数据类型

1、Jedis操作Redis各种数据结构案例

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.junit.BeforeClass;
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class JedisTest {
    static Jedis jedis;
    @BeforeClass
    public static void beforeClass() {
        jedis = new Jedis("115.28.65.149");
    }
    // Redis和Java字符串实例
    @Test
    public void testString() {
        // set the data in redis string
        jedis.set("tutorial-name", "Redis tutorial");
        // Get the stored data and print it
        System.out.println("Stored string in redis:: " + jedis.get("tutorial-name"));
        // 输出:Stored string in redis:: Redis tutorial
    }
    // Redis和Java列表示例
    @Test
    public void testList() {
        jedis.lpush("tutorial-list", "Redis");
        jedis.lpush("tutorial-list", "Mongodb");
        jedis.lpush("tutorial-list", "Mysql");
        // Get the stored data and print it
        List<String> list = jedis.lrange("tutorial-list", 0, 5);
        for (int i = 0; i < list.size(); i++) {
            System.out.println("Stored string in redis:: " + list.get(i));
        }
        /*
         * 输出 Stored string in redis:: Mysql Stored string in redis:: Mongodb Stored
         * string in redis:: Redis
         */
    }
    // Redis和Java的键实例
    @Test
    public void testKeys() {
        Set<String> keys = jedis.keys("*");
        for (String key : keys) {
            System.out.println("List of stored keys:: " + key);
        }
        /*
         * 输出 List of stored keys:: tutorial-name List of stored keys:: tutorial-list
         */
    }
    // Redis和Java的hash实例
    @Test
    public void testHash() {
        String key = "user";
        String field_name = "name";
        String field_name_value = "tianshouzhi";
        String field_city = "city";
        String field_city_value = "shanghai";
        jedis.hset(key, field_name, field_name_value);
        jedis.hset(key, field_city, field_city_value);
        Map<String, String> map = jedis.hgetAll(key);
        Set<Entry<String, String>> entrySet = map.entrySet();
        for (Entry<String, String> entry : entrySet) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        /*
         * 输出 name:tianshouzhi city:shanghai
         */
    }
    // Redis和Java的集合实例
    @Test
    public void testSet() {
        String key = "set_key";
        String[] members = new String[] { "a", "b", "a", "c" };
        jedis.sadd(key, members);
        Set<String> smembers = jedis.smembers(key);
        for (String string : smembers) {
            System.out.println(string);
        }
        /*
         * 输出 name:tianshouzhi city:shanghai
         */
    }
    // Redis和Java的集合实例
    @Test
    public void testZSet() {
        String key = "zset_key";
        Map<String, Double> scoreMembers = new HashMap<String, Double>();
        jedis.zadd(key, scoreMembers);
        Set<String> zrange = jedis.zrange(key, 0, 2);
        for (String member : zrange) {
            System.out.println(member);
            System.out.println(jedis.zscore(key, member));
        }
        /*
         * 输出 tianshouzhi 1.0 huhuamin 2.0
         */
    }
}

2、Jedis 通知

// 订阅:需要先执行订阅操作
// 覆盖JedisPubSub中的onMessage,用于回调
@Test
public void testSubsribe() {
    JedisPubSub jedisPubSub = new JedisPubSub() {
        @Override
        public void onMessage(String channel, String message) {
            System.out.println(channel);
            System.out.println(message);
        }
    };
    jedis.subscribe(jedisPubSub, "channel1");
    /*
     * 输出 channel1 test publish substribe
     */
}
// 发布
@Test
public void testPublish() {
    String channel = "channel1";
    String message = "test publish substribe";
    jedis.publish(channel, message);
}

订阅一个channel,需要先用一个client来订阅。然后再publish消息到这个channel中,所以我们需要先执行testSubsribe,再执行testPublish。需要注意的是,JedisPubSub是在后台运行的,因此可以重复不断的接受消息。
需要注意的是,因为发布订阅模型中,一条消息被所有订阅次channel的client接受到。有的业务场景下,可能不满足我们要的要求,例如处理订单,我们可能只需要一个Client来处理。此时我们需要使用到阻塞队列。

3、阻塞队列

为了演示阻塞队列的功能,我们启动2个客户端,一个是java客户端,一个是redis-cli客户端,都从列表queue中使用brpop获取数据。
redis-cli客户端
QQ截图20160320003724.png
Java客户端

@Test
public void testBlockedQueue() {
    List<String> brpop = jedis.brpop(0, "queue");
    for (String string : brpop) {
        System.out.println(string);
    }
}

运行这个测试方法,也会进入阻塞状态。
往queue中放入消息

@Test
public void testLpush() {
    jedis.lpush("queue", "queue_message1", "queue_message2");
}

执行这段代码,我们将会看到两个客户端分别接受到了一条消息,而不是每条消息被共享。
redis-cli接受到queue_message1
QQ截图20160320004006.png
Java客户端接受到

queue
queue_message2

需要注意的是,阻塞队列接受到一条消息之后,就会跳出阻塞状态。如果需要不断的循环监听,则要使用while(true)将这段代码包含起来,如

// 阻塞队列
@Test
public void testBlockedQueue() {
    while (true) {
        List<String> brpop = jedis.brpop(0, "queue");
        for (String string : brpop) {
            System.out.println(string);
        }
    }
}

此时,我们在执行testLpush方法,看到控制台输出

queue
queue_message1
queue
queue_message2

从现实的结果中,我们可以看出以下这段代码的返回值的组成

List<String> brpop = jedis.brpop(0,"queue");

List中的元素总是偶数个,其中奇数表示的从哪一个队列中监听到的消息,偶数表示消息的内容。

使用 pipeline

如果希望一次发送一批 redis 命令,一种有效的方式是使用 pipeline。
jedis 使用 pipeline 的代码如下:

Pipeline p = jedis.pipelined();
p.set("fool", "bar");
p.zadd("foo", 1, "barowitch"); p.zadd("foo", 0, "barinsky"); p.zadd("foo", 0, "barikoviev");
Response<String> pipeString = p.get("fool");
Response<Set<String>> sose = p.zrange("foo", 0, -1);
p.sync();
int soseSize = sose.get().size();
Set<String> setBack = sose.get();

使用 transaction

如果希望一些命令一起执行而不被干扰,可以通过 transaction 将命令打包到一起执行:

jedis.watch (key1, key2, ...);
BinaryTransaction t = jedis.multi();
t.set("foo", "bar");
t.exec();

如果需要得到返回值,可以参考下面的代码:

Transaction t = jedis.multi();
t.set("fool", "bar");
Response<String> result1 = t.get("fool");
t.zadd("foo", 1, "barowitch"); t.zadd("foo", 0, "barinsky"); t.zadd("foo", 0, "barikoviev");
Response<Set<String>> sose = t.zrange("foo", 0, -1); // get the entire sortedset
t.exec(); // dont forget it
String foolbar = result1.get(); // use Response.get() to retrieve
things from a Response
int soseSize = sose.get().size(); // on sose.get() you can directly
call Set methods!

5.2 ShardedJedis

简单的说, ShardedJedis 是一种帮助提高读/写并发能力的群集,群集使用一致性 hash 来确保一个 key 始终被指向相同的 redis server。每个 redis server 被称为一个 shard。
因为每个 shard 都是一个 master,因此使用 sharding 机制会产生一些限制:不能在 sharding中直接使用 jedis 的 transactions、pipelining、pub/sub 这些 API,基本的原则是不能跨越 shard。但 jedis 并没有在 API 的层面上禁止这些行为,但是这些行为会有不确定的结果。一种可能的方式是使用 keytags 来干预 key 的分布,当然,这需要手工的干预。
另外一个限制是正在使用的 shards 是不能被改变的,因为所有的 sharding 都是预分片的。
注:如果希望使用可以改变的 shards,可以使用 yaourt – dynamic sharding implementation(一个jedis 的实现分支)。

ShardedJedis 的使用方法:

1. 定义 shards:

List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
JedisShardInfo si = new JedisShardInfo("localhost", 6379);
si.setPassword("foobared");
shards.add(si);
si = new JedisShardInfo("localhost", 6380);
si.setPassword("foobared");
shards.add(si);

2.a) 直接使用:

ShardedJedis jedis = new ShardedJedis(shards);
jedis.set("a", "foo");
jedis.disconnect;

2.b) 或 使用连接池:

ShardedJedisPool pool = new ShardedJedisPool(new Config(), shards);
ShardedJedis jedis = pool.getResource();
jedis.set("a", "foo");
.... // do your work here
pool.returnResource(jedis);
.... // a few moments later
ShardedJedis jedis2 = pool.getResource();
jedis.set("z", "bar");
pool.returnResource(jedis);
pool.destroy();

判断使用的是那个 shards:

ShardInfo si = jedis.getShardInfo(key);
si.getHost/getPort/getPassword/getTimeout/getName

也可以通过 keytags 来确保 key 位于相同的 shard。如:

ShardedJedis jedis = new ShardedJedis(shards,
ShardedJedis.DEFAULT_KEY_TAG_PATTERN);

这样,默认的 keytags 是”{}”,这表示在”{}”内的字符会用于决定使用那个 shard。如:

jedis.set("foo{bar}", "12345");

jedis.set("car{bar}", "877878");

会使用同一个 shard。
注:如果 key 和 keytag 不匹配,会使用原来的 key 作为选择 shard 的 key。

使用 ShardedJedisPipeline

ShardedJedisPipeline 其实是一个很鸡肋的功能。
为了能在 ShardedJedis 中平滑的支持 redis 的 pipeline 的功能, ShardedJedis 通过ShardedJedisPipeline 类对 pipeline 提供了支持。
简单的说, ShardedJedis 是通过向每个用到的 shard 发起 pipeline 来实现 ShardedJedisPipeline的功能,这种方式如果累积的 key 不够多,很难达到提高效率的目的。
如果需要在 ShardedJedis 中使用 pipeline,还是建议尽量通过 keytag 将关联的 key 放到同一shard 之中。
ShardedJedisPipeline 简单的示例代码如下:

ShardedJedis jedis = new ShardedJedis(shards);
ShardedJedisPipeline p = jedis.pipelined();
p.set("foo", "bar");
p.get("foo");
List<Object> results = p.syncAndReturnAll();
//assertEquals(2, results.size());
//assertEquals("OK", results.get(0));
//assertEquals("bar", results.get(1));

ShardedJedisPipeline 相对复杂的示例代码:

ShardedJedis jedis = new ShardedJedis(shards);
jedis.set("string", "foo");
jedis.lpush("list", "foo");
jedis.hset("hash", "foo", "bar");
jedis.zadd("zset", 1, "foo");
jedis.sadd("set", "foo");
ShardedJedisPipeline p = jedis.pipelined();
Response<String> string = p.get("string");
Response<Long> del = p.del("string");
Response<String> emptyString = p.get("string");
Response<String> list = p.lpop("list");
Response<String> hash = p.hget("hash", "foo");
Response<Set<String>> zset = p.zrange("zset", 0, -1);
Response<String> set = p.spop("set");
Response<Boolean> blist = p.exists("list");
Response<Double> zincrby = p.zincrby("zset", 1, "foo");
Response<Long> zcard = p.zcard("zset");
p.lpush("list", "bar");
Response<List<String>> lrange = p.lrange("list", 0, -1);
Response<Map<String, String>> hgetAll = p.hgetAll("hash");
p.sadd("set", "foo");
Response<Set<String>> smembers = p.smembers("set");
Response<Set<Tuple>> zrangeWithScores = p.zrangeWithScores("zset", 0,-1);
p.sync();
assertEquals("foo", string.get());
assertEquals(Long.valueOf(1), del.get());
assertNull(emptyString.get());
assertEquals("foo", list.get());
assertEquals("bar", hash.get());
assertEquals("foo", zset.get().iterator().next());
assertEquals("foo", set.get());
assertFalse(blist.get());
assertEquals(Double.valueOf(2), zincrby.get());
assertEquals(Long.valueOf(1), zcard.get());
assertEquals(1, lrange.get().size());
assertNotNull(hgetAll.get().get("foo"));
assertEquals(1, smembers.get().size());
assertEquals(1, zrangeWithScores.get().size());

ShardedJedis实现分析

ShardedJedis是基于一致性哈希算法实现的分布式Redis集群客户端;ShardedJedis的设计分为以下几块:

  • 对象池设计:Pool,ShardedJedisPool,ShardedJedisFactory
  • 面向用户的操作封装:BinaryShardedJedis,BinaryShardedJedis
  • 一致性哈希实现:Sharded

关于ShardedJedis设计,忽略了Jedis的设计细节,设计类图如下:
8bd3b170-018d-36a2-b2e5-44cde24caceb.jpg
关于ShardedJedis类图设计,省略了对象池,以及Jedis设计的以下细节介绍:

类名 职责
Sharded 抽象了基于一致性哈希算法的划分设计,设计思路
  1. 基于hash算法划分redis服务器
  2. 保持每台Redis服务器的Jedis客户端
  3. 提供基于Key的划分方法;提供了ShardKeyTag实现
BinaryShardedJedis 同BinaryJedis类似,实现BinaryJedisCommands对外提供基于Byte[]的key,value操作
ShardedJedis 同Jedis类似,实现JedisCommands对外提供基于String的key,value操作

shared一致性哈希采用以下方案:

  1. Redis服务器节点划分:将每台服务器节点采用hash算法划分为160个虚拟节点(可以配置划分权重)
  2. 将划分虚拟节点采用TreeMap存储
  3. 对每个Redis服务器的物理连接采用LinkedHashMap存储
  4. 对Key or KeyTag 采用同样的hash算法,然后从TreeMap获取大于等于键hash值得节点,取最邻近节点存储;当key的hash值大于虚拟节点hash值得最大值时,存入第一个虚拟节点

sharded采用的hash算法:MD5 和 MurmurHash两种;默认采用64位的MurmurHash算法;有兴趣的可以研究下,MurmurHash是一种高效,低碰撞的hash算法;
参考地址:
http://blog.csdn.net/yfkiss/article/details/7337382
https://sites.google.com/site/murmurhash/

5.3 使用 jedis 的对象池

jedis 通过 commons-pool 来提供其对象池的功能,其对象池类有 JedisPool 和 ShardedJedisPool,面向普通的 redis 连接池和 pre-sharding 的 redis 连接池。
在连接池的使用和配置层面,这两个类基本没什么差别。
配置 jedis 的连接池,一般通过 JedisPoolConfig 类完成,其提供了一个不同于基类的默认值,当然也可以通过 org.apache.commons.pool.impl.GenericObjectPool.Config 类来配置,这个类的默认值我们可以在 commons-pool 对象池配置的小节中看到。

对象池的使用

jedis 创建对象池的方式:

JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost");

使用池中的对象,是通过 JedisPool 的 getResource 和 returnResource 来得到和归还资源:

Jedis jedis = pool.getResource();
try {
    /// ... do stuff here ... for example
    jedis.set("foo", "bar");
    String foobar = jedis.get("foo");
    jedis.zadd("sose", 0, "car");
    jedis.zadd("sose", 0, "bike");
    Set<String> sose = jedis.zrange("sose", 0, -1);
} catch (JedisConnectionException e) {
    // returnBrokenResource when the state of the object is unrecoverable
    if (null != jedis) {
        pool.returnBrokenResource(jedis);
        jedis = null;
    }
} finally {
    /// ... it's important to return the Jedis instance to the pool once you've
    /// finished using it
    if (null != jedis)
        pool.returnResource(jedis);
}
/// ... when closing your application:
pool.destroy();

commons-pool 对象池配置

jedis 的对象池是通过apache的commons-pool实现的。 其对象池的配置是通过org.apache.commons.pool.impl.GenericObjectPool.Config 类完成。
Config 是一个简单的值对象类,其成员都有预设的默认值。
我们将 Config 类的各个成员的配置含义描述如下:

  • maxActive

控制池中对象的最大数量。默认值是 8,如果是负值表示没限制。

  • maxIdle

控制池中空闲的对象的最大数量。默认值是 8,如果是负值表示没限制。

  • minIdle

控制池中空闲的对象的最小数量。默认值是 0。

  • whenExhaustedAction

指定池中对象被消耗完以后的行为,有下面这些选择:
>> WHEN_EXHAUSTED_FAIL 0
>> WHEN_EXHAUSTED_GROW 2
>> WHEN_EXHAUSTED_BLOCK 1
如果是 WHEN_EXHAUSTED_FAIL,当池中对象达到上限以后,继续 borrowObject 会抛出NoSuchElementException 异常。
如果是 WHEN_EXHAUSTED_GROW,当池中对象达到上限以后,会创建一个新对象,并返回它。
如果是 WHEN_EXHAUSTED_BLOCK,当池中对象达到上限以后, 会一直等待,直到有一个对象可用。 这个行为还与 maxWait 有关,如果 maxWait 是正数,那么会等待 maxWait 的毫秒的时间,超时会抛出 NoSuchElementException 异常;如果 maxWait 为负值,会永久等待。
whenExhaustedAction 的默认值是 WHEN_EXHAUSTED_BLOCK, maxWait 的默认值是-1。

  • maxWait

whenExhaustedAction 如果是 WHEN_EXHAUSTED_BLOCK,指定等待的毫秒数。如果 maxWait是正数,那么会等待 maxWait 的毫秒的时间,超时会抛出 NoSuchElementException 异常;如果 maxWait 为负值,会永久等待。maxWait 的默认值是-1。

  • testOnBorrow

如果 testOnBorrow 被设置, pool 会在 borrowObject 返回对象之前使用 PoolableObjectFactory的 validateObject 来验证这个对象是否有效,要是对象没通过验证,这个对象会被丢弃,然后重新选择一个新的对象。testOnBorrow 的默认值是 false。

  • testOnReturn

如果 testOnReturn 被设置, pool 会在 returnObject 的时候通过 PoolableObjectFactory 的validateObject 方法验证对象,如果对象没通过验证,对象会被丢弃,不会被放到池中。testOnReturn 的默认值是 false。

  • testWhileIdle

指定 idle 对象是否应该使用 PoolableObjectFactory 的 validateObject 校验,如果校验失败,这个对象会从对象池中被清除。这个设置仅在 timeBetweenEvictionRunsMillis 被设置成正值( >0) 的时候才会生效。testWhileIdle 的默认值是 false。

  • timeBetweenEvictionRunsMillis

指定驱逐线程的休眠时间。如果这个值不是正数( >0),不会有驱逐线程运行。timeBetweenEvictionRunsMillis 的默认值是-1。

  • numTestsPerEvictionRun

设置驱逐线程每次检测对象的数量。这个设置仅在 timeBetweenEvictionRunsMillis 被设置成正值( >0)的时候才会生效。numTestsPerEvictionRun 的默认值是 3。

  • minEvictableIdleTimeMillis

指定最小的空闲驱逐的时间间隔(空闲超过指定的时间的对象,会被清除掉)。这个设置仅在 timeBetweenEvictionRunsMillis 被设置成正值( >0)的时候才会生效。minEvictableIdleTimeMillis 默认值是 30 分钟。

  • softMinEvictableIdleTimeMillis

与 minEvictableIdleTimeMillis 类似,也是指定最小的空闲驱逐的时间间隔(空闲超过指定的时间的对象,会被清除掉),不过会参考 minIdle 的值,只有 idle 对象的数量超过 minIdle 的值,对象才会被清除。
这个设置仅在 timeBetweenEvictionRunsMillis 被设置成正值( >0)的时候才会生效,并且这个配置能被 minEvictableIdleTimeMillis 配置取代( minEvictableIdleTimeMillis 配置项的优先级更高)。softMinEvictableIdleTimeMillis 的默认值是-1。

  • lifo

pool 可以被配置成 LIFO 队列( last-in-first-out)或 FIFO 队列( first-in-first-out),来指定空闲对象被使用的次序。lifo 的默认值是 true。

JedisPoolConfig 的调整

jedis 的对象池是通过 commons-pool 实现的,对对象池的配置应该通过 JedisPoolConfig 来完成, jedis 提供了自己的配置参数:

public class JedisPoolConfig extends Config {
    public JedisPoolConfig() {
        // defaults to make your life with connection pool easier :)
        setTestWhileIdle(true);
        setMinEvictableIdleTimeMillis(60000);
        setTimeBetweenEvictionRunsMillis(30000);
        setNumTestsPerEvictionRun(-1);
    }
}

简单的说,是启用了 commons-pool 的驱逐线程,并配置了驱逐线程的轮询参数。

作者:田守芝

来源:http://www.tianshouzhi.com/api/tutorials/redis/199


版权声明:文末如注明作者和来源,则表示本文系转载,版权为原作者所有 | 本文如有侵权,请及时联系,承诺在收到消息后第一时间删除 | 如转载本文,请注明原文链接。
喜欢 (0)