Jedis实例不是线程安全的,所以不可以多个线程共用一个Jedis实例,但是创建太多的实现也不好因为这意味着会建立很多sokcet连接。
JedisPool是一个线程安全的网络连接池。可以用JedisPool创建一些可靠Jedis实例,可以从池中获取Jedis实例,使用完后再把Jedis实例还回JedisPool。这种方式可以避免创建大量socket连接并且会实现高效的性能.
JedisPool初始化
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 设置最大10个连接
jedisPoolConfig.setMaxTotal(10);
pool = new JedisPool(jedisPoolConfig, "localhost");
- 1
- 2
- 3
- 4
使用JedisPool
1.JedisPool#getResource()
方法从连接池中取得一个Jedis实例,
2.使用Jedis实例进行正常的数据操作
3.Jedis实例使用完后要把它再放回连接池。
资源释放
关于如何将使用完后的Jedis实例还回连接池,网上看到的大部分文章都是建议用JedisPool#returnResource
方法,这些文章大多是3,4年前的文章
jedis官网:https://github.com/xetorthio/jedis,
而当我使用jedis时,jedis的最新版本已经到了2.9(我使用的是2.8.2)。
在jedis2.8.2中已经将JedisPool#returnResource
方法废弃了,并明确说明这个方法的功能由Jedis.close()
方法代替。
void redis.clients.jedis.JedisPool.returnResource(Jedis resource)
@Override
@Deprecated
不推荐. starting from Jedis 3.0 this method will not be exposed. Resource cleanup should be done using @see redis.clients.jedis.Jedis.close()
本文作者注:从Jedis 3.0开始这个方法将不再暴露给外部(public),资源清除应该调用用Jedis.close()方法
覆盖: Pool 中的 returnResource(...)
参数:resource
- 1
- 2
- 3
- 4
- 5
- 6
- 7
如果进一步查看Jedis#close()
方法的源码,会发现,close()
方法最终依然是调用 JedisPool#returnResource
方法。
可以看到,当使用JedisPool时,close方法并没有真的执行client.close方法,只是将它还给JedisPool连接池,以供下次使用。
@Override
public void close() {
if (dataSource != null) {
// dataSource 即为 JedisPool实例,
if (client.isBroken()) {
// 调用 JedisPool#returnBrokenResource方法
this.dataSource.returnBrokenResource(this);
} else {
// 调用 JedisPool#returnResource 方法
this.dataSource.returnResource(this);
}
} else {
client.close();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
所以正确使用并释放连接池资源的方式如下:
Jedis jedis = null;
try{
// 从连接池获取一个Jedis实例
jedis = pool.getResource();
//设置 redis 字符串数据 SET 10km blog.csdn.net/10km
jedis.set("10km", "blog.csdn.net/10km");
// 获取存储的数据并输出
System.out.println("redis 存储的字符串为: "+ jedis.get("10km"));
}finally{
if(null != jedis)
jedis.close(); // 释放资源还给连接池
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
完整Junit测试代码
package net.gdface.facelog;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestRedis {
private JedisPool pool;
/**
* 初始化连接池
*/
@Before
public void init() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(10);
pool = new JedisPool(jedisPoolConfig, "localhost");
System.out.println("连接池初始化成功");
}
@Test
public void testPing(){
// Jedis 实现了java.lang.AutoCloseable接口,所以这里可以用java 1.7 try-with-resources语法自动完成close
try(Jedis jedis = pool.getResource()){
//查看服务是否运行 PING
System.out.println("服务正在运行: "+jedis.ping());
}
}
@Test
public void testString(){
try(Jedis jedis = pool.getResource()){
//设置 redis 字符串数据 SET 10km blog.csdn.net/10km
jedis.set("10km", "blog.csdn.net/10km");
// 获取存储的数据并输出
System.out.println("redis 存储的字符串为: "+ jedis.get("10km"));
}
}
@Test
public void testList() {
try (Jedis jedis = pool.getResource()) {
// 选择数据库: SELECT 2
jedis.select(2);
// 存储数据到列表中
// LPUSH
jedis.lpush("phone_list", "Apple");
jedis.lpush("phone_list", "Huawei");
jedis.lpush("phone_list", "XiaoMi");
// 获取存储的数据并输出: LRANGE phone_list 0 2
List<String> list = jedis.lrange("phone_list", 0, 2);
for (int i = 0; i < list.size(); i++) {
System.out.println("phone_list 列表项为: " + list.get(i));
}
}
}
/**
* 程序关闭时,需要调用关闭方法
*/
@After
public void end(){
if(null != pool){
pool.destroy();
System.out.println("连接池关闭");
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74