我们在使用jedis操作redis数据库时如果使用以下方法进行数据库操作的话
void setUp() {
jedis = new Jedis();
jedis.auth("password");
jedis.select(0);
}
会在每次数据库操作时进行new Jedis()操作
void tearDown() {
if (jedis != null) {
jedis.close();
}
}
并且在操作结束后销毁连接,这样的话会产生一些问题
(1)耗时:建立与redis的连接或经过TCP三次握手,身份验证等步骤,如果每次数据库操作都新建一个连接,而又在操作结束后销毁连接,会带来很大的系统性能损耗。
(2)无法控制连接数量:在多线程高并发的情况下同时处理大量请求,建立过多与redis的连接导致系统资源耗尽甚至系统崩溃。
所以我们通过配置连接池的方法建立与redis的连接,同时防止以上情况的发生:
public class JedisConnectionFactory {
private static final JedisPool jedisPool;
static{
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 设置连接池中的最大连接数为 8
jedisPoolConfig.setMaxTotal(8);
// 设置连接池中的最大空闲连接数为 8
jedisPoolConfig.setMaxIdle(8);
// 设置连接池中的最小空闲连接数为 0
jedisPoolConfig.setMinIdle(0);
jedisPool = new JedisPool(jedisPoolConfig,"localhost",6379,1000,"password");
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
static在这里的作用
1.保证单例
连接池的初始化是一个相对耗时的操作,而且在整个应用生命周期中只需要一个连接池实例来统一管理后端服务器与redis服务器的连接,所以根据连接池单例的特性利用static静态代码块只在类加载时执行一次的特性,在类加载时初始化连接池到JVM中,减少资源浪费。
2.线程安全
静态代码块在类加载时由JVM负责,JVM规范要求每个类或接口在第一次使用时初始化,在多线程情况下,JVM能保证类或接口在初始化时是线程安全的。具体原因如下:
JVM在类加载时的同步机制:JVM会对每个类或接口维护一个初始化锁,每个线程会尝试是初始化该类,获得初始化锁。如果该类还未被初始化,那么该线程就是该类的初始化线程。在类的初始化过程中,JVM会阻塞其他线程获取该锁,直到初始化完成释放该锁,从而避免了多线程同时获取到未初始化状态的的锁而对当前类进行初始化操作。
使用连接池后我们不在需要每次建立新的连接而是通过连接池统一管理
void setUp() {
jedis = JedisConnectionFactory.getJedis();
jedis.auth("2101");
jedis.select(0);
}
同时在结束操作后不再销毁连接,而是将连接归还给连接池
void tearDown() {
if (jedis != null) {
jedis.close();
}
}
通过连接池配置 Jedis 主要有以下几个方面的好处:
-
减少连接创建和销毁开销 连接池在初始化时会创建一定数量的连接并保存在池中,当需要使用连接时,直接从池中获取,使用完后再归还到池中,避免了频繁创建和销毁连接的开销,显著提升了系统的响应速度。
-
提高系统性能和吞吐量 连接池可以对连接进行统一管理和复用,能够在高并发场景下更高效地处理大量请求。当多个线程同时需要与 Redis 交互时,连接池可以快速分配可用连接,减少线程等待时间,从而提高系统的整体性能和吞吐量。
-
资源控制和管理 通过连接池配置,可以对连接的数量进行有效控制。例如,可以设置最大连接数、最大空闲连接数和最小空闲连接数等参数。这有助于防止系统因为创建过多连接而耗尽服务器资源,导致系统崩溃或性能急剧下降。同时,连接池还可以对连接进行健康检查,自动回收无效连接,保证连接的可用性。
-
方便连接的维护和监控 连接池提供了统一的接口来管理连接,可以方便地对连接进行维护和监控。例如,可以统计连接的使用情况、监控连接的生命周期等,有助于及时发现和解决潜在的问题。