Java数据库连接池原理与简易实现

简介: Java数据库连接池原理与简易实现

1、什么是数据库连接池

我们现在在开发中一定都会用到数据库,为了提高我们的系统的访问速度,数据库优化是一个有效的途径。


我们现在开发中使用数据库一般都要经历以下的四个步骤:

(1)加载数据库的驱动类,

(2)建立数据库连接,

(3)进行数据操作,

(4)关闭数据库连接;


在这四步中建立数据库连接是一个比较耗时的操作,如果每次有新的操作数据库的需求都去重新建立数据库连接必然要耗费一部分时间,拖慢系统的访问速度;在这种情况下我们就需要数据库连接池,预先创建好一定数量的数据库连接,等我们现需要使用时直接从其中拿已经创建好了尚未使用的的数据库连接,这样就可以节省掉一部分时间,加快系统的访问速度,保存这些预先创建的一定数量的数据库连接的容器称之为数据库连接池。


2、现有的常用数据库连接池

(1)DBCP数据库连接池

(2)C3P0数据库连接池


3、数据库连接池原理

数据库连接池通过预先创建一定数量的空闲的数据库连接,在需要数据库连接时直接从其中获取,而不要去重新创建而节省一定的时间。


数据库连接池的连接有连个属性,一个是本数据库的真正的连接对象,一个是标志本连接是否是空闲的标志;当数据库连接池被初始化的时候,会去创建一定数量(一般在配置文件中配置)的数据库连接,并且这些连接都是处于空闲状态的,当需要数据库连接时,直接从数据库连接池中获取已经创建并且空闲的数据库连 接 并将其致为非空闲状态,如果数据库连接池中没有了空闲的连接,则去看数据库连接池连接数量是否以达到最大值(一般在配置文件中配置),如果没有达到最 大 值则再去创建一定数量的空闲连接;当连接使用完毕后,并不真正的关闭连接,而是将连接的状态重新致为空闲。从而达到连接重复使用的效果,节省时间。


4、简易数据库连接池的实现

(1)、创建数据库连接池的对象,对象包括真正的数据库连接池对象和是否可用的标志。

importjava.sql.Connection;
importjava.sql.ResultSet;
importjava.sql.SQLException;
importjava.sql.Statement;
/*** 数据库连接池对象*/publicclassSimplePoolEntity {
//真正的数据库连接对象privateConnectionconnection;
//是否可用的标志,默认为true 可用privatebooleanisUsable=true;
publicConnectiongetConnection() {
returnconnection;
    }
publicvoidsetConnection(Connectionconnection) {
this.connection=connection;
    }
publicbooleanisUsable() {
returnisUsable;
    }
publicvoidsetUsable(booleanusable) {
isUsable=usable;
    }
/*** 数据库操作方法* @param sql  需要执行的sql语句* @return  ResultSet*/publicResultSetexecSql(Stringsql){
ResultSetrs=null;
try {
Statementstatement=connection.createStatement();
rs=statement.executeQuery(sql);
        } catch (SQLExceptione) {
e.printStackTrace();
        }
returnrs;
    }
}


(2)数据库连接池操作接口

/*** 数据库连接池操作接口*/publicinterfaceSimplePoolService {
/*** 连接池创建连接接口* @param connCount  需要创建的连接数量*/voidcreateConnection(intconnCount) throwsException;
/*** 获取数据库连接* @return* @throws Exception*/SimplePoolEntitygetConnection();
}

(3)数据库连接池操作实现

数据库连接池配置文件:

#数据库的驱动类simple.jdbc.driver=com.mysql.jdbc.Driver#数据库的连接urlsimple.jdbc.url=jdbc:mysql://localhost:3306/test#数据库的连接用户名simple.jdbc.username=root#数据库的连接密码simpel.jdbc.password=root#数据库连接池的初始化连接数量simple.init.count=10#数据库连接池的步进数量simple.step.count=4#连接池的最大数量simple.max.count=100


数据库连接池的实现

/**数据库操作实现本操作中将要实现数据库连接池的初始化工作,初始化参数采用配置文件的形式来进行配置 */publicclassSimplePoolServiceImplimplementsSimplePoolService {
privateStringjdbcDriver; // 数据库驱动privateStringjdbcUrl;  //数据库urlprivateStringusername; //用户名privateStringpassword; //密码privateIntegerinitCount; //初始化数量privateIntegerstepCount;  //步进数量privateIntegermaxCount; //最大数量privateSimplePoolEntitysimplePoolEntity;
privateSet<SimplePoolEntity>simplePoolEntitySet=newHashSet<>();
/*** 构造方法初始化 数据库连接池*/publicSimplePoolServiceImpl(){
init();
    }
/*** 数据库连接池初始化*/privatevoidinit(){
//1.读取配置文件InputStreamin=this.getClass().getClassLoader().getResourceAsStream("simpleboolconfig.properties");
Propertiesproperties=newProperties();
try {
properties.load(in);
//设置初始化参数jdbcDriver=properties.getProperty("simple.jdbc.driver");
jdbcUrl=properties.getProperty("simple.jdbc.url");
username=properties.getProperty("simple.jdbc.username");
password=properties.getProperty("simpel.jdbc.password");
initCount=Integer.parseInt(properties.getProperty("simple.init.count"));
stepCount=Integer.parseInt( properties.getProperty("simple.step.count"));
maxCount=Integer.parseInt( properties.getProperty("simple.max.count"));
//加载数据库驱动Driverdriver= (Driver) Class.forName(jdbcDriver).newInstance();
//获取数据库管理对象DriverManager.deregisterDriver(driver);
//初始化一定数量的连接createConnection(initCount);
        } catch (Exceptione) {
e.printStackTrace();
        }
    }
@OverridepublicvoidcreateConnection(intconnCount) throwsException {
//判断数据库连接池是否以达到最大连接数if(simplePoolEntitySet.size() +connCount>maxCount){
thrownewRuntimeException("连接池数量已到上限");
        }
for (inti=0;i<connCount;i++){
simplePoolEntity=newSimplePoolEntity();
simplePoolEntity.setConnection(DriverManager.getConnection(jdbcUrl,username,password));
simplePoolEntity.setUsable(true);
simplePoolEntitySet.add(simplePoolEntity);
        }
    }
@OverridepublicSimplePoolEntitygetConnection()  {
try {
SimplePoolEntitysimplePoolEntity=getRealConection();
//为空时创建新的连接while (simplePoolEntity==null){
createConnection(stepCount);
//创建连接比较耗时,建议在此处让线程延迟一定时间Thread.sleep(3000);
simplePoolEntity=getRealConection();
            }
        } catch (Exceptione) {
e.printStackTrace();
        }
returnsimplePoolEntity;
    }
privateSimplePoolEntitygetRealConection() throwsException{
//循环连接池,获取连接for(SimplePoolEntitysimplePoolEntity : simplePoolEntitySet){
//判断是否为空闲if(simplePoolEntity.isUsable()){
//判断连接是否有效if(!simplePoolEntity.getConnection().isValid(3000)){
//无效连接,重新创建连接替换该连接ConnectionrealConnect=DriverManager.getConnection(jdbcUrl,username,password);
simplePoolEntity.setConnection(realConnect);
                }
//设置状态为不可用simplePoolEntity.setUsable(false);
returnsimplePoolEntity;
            }
        }
returnnull;
    }
}



 (4) 对外提供单例模式的数据库连接池管理对象


publicclassSimplePoolManger { 
//私有化构造,禁止创建 privateSimplePoolManger(){}
//在静态内部类中实例化对象,达到懒汉单例模式privatestaticclassClassLoad{
publicstaticSimplePoolServicegetSimplePoolService(){
returnnewSimplePoolServiceImpl();
         }
    }
publicstaticSimplePoolServicegetInstace(){
returnClassLoad.getSimplePoolService();
    }
}


相关文章
|
17天前
|
安全 Java API
JAVA并发编程JUC包之CAS原理
在JDK 1.5之后,Java API引入了`java.util.concurrent`包(简称JUC包),提供了多种并发工具类,如原子类`AtomicXX`、线程池`Executors`、信号量`Semaphore`、阻塞队列等。这些工具类简化了并发编程的复杂度。原子类`Atomic`尤其重要,它提供了线程安全的变量更新方法,支持整型、长整型、布尔型、数组及对象属性的原子修改。结合`volatile`关键字,可以实现多线程环境下共享变量的安全修改。
|
13天前
|
算法 Java
JAVA并发编程系列(8)CountDownLatch核心原理
面试中的编程题目“模拟拼团”,我们通过使用CountDownLatch来实现多线程条件下的拼团逻辑。此外,深入解析了CountDownLatch的核心原理及其内部实现机制,特别是`await()`方法的具体工作流程。通过详细分析源码与内部结构,帮助读者更好地理解并发编程的关键概念。
|
21天前
|
存储 关系型数据库 MySQL
【Java面试题汇总】MySQL数据库篇(2023版)
聚簇索引和非聚簇索引、索引的底层数据结构、B树和B+树、MySQL为什么不用红黑树而用B+树、数据库引擎有哪些、InnoDB的MVCC、乐观锁和悲观锁、ACID、事务隔离级别、MySQL主从同步、MySQL调优
【Java面试题汇总】MySQL数据库篇(2023版)
|
12天前
|
Java
JAVA并发编程系列(9)CyclicBarrier循环屏障原理分析
本文介绍了拼多多面试中的模拟拼团问题,通过使用 `CyclicBarrier` 实现了多人拼团成功后提交订单并支付的功能。与之前的 `CountDownLatch` 方法不同,`CyclicBarrier` 能够确保所有线程到达屏障点后继续执行,并且屏障可重复使用。文章详细解析了 `CyclicBarrier` 的核心原理及使用方法,并通过代码示例展示了其工作流程。最后,文章还提供了 `CyclicBarrier` 的源码分析,帮助读者深入理解其实现机制。
|
5天前
|
安全 Java 编译器
Java反射的原理
Java 反射是一种强大的特性,允许程序在运行时动态加载、查询和操作类及其成员。通过 `java.lang.reflect` 包中的类,可以获取类的信息并调用其方法。反射基于类加载器和 `Class` 对象,可通过类名、`getClass()` 或 `loadClass()` 获取 `Class` 对象。反射可用来获取构造函数、方法和字段,并动态创建实例、调用方法和访问字段。虽然提供灵活性,但反射会增加性能开销,应谨慎使用。常见应用场景包括框架开发、动态代理、注解处理和测试框架。
|
12天前
|
Java
Java的aop是如何实现的?原理是什么?
Java的aop是如何实现的?原理是什么?
15 4
|
16天前
|
存储 Java
JAVA并发编程AQS原理剖析
很多小朋友面试时候,面试官考察并发编程部分,都会被问:说一下AQS原理。面对并发编程基础和面试经验,专栏采用通俗简洁无废话无八股文方式,已陆续梳理分享了《一文看懂全部锁机制》、《JUC包之CAS原理》、《volatile核心原理》、《synchronized全能王的原理》,希望可以帮到大家巩固相关核心技术原理。今天我们聊聊AQS....
|
13天前
|
监控 算法 Java
深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。
|
11天前
|
存储 缓存 Java
JAVA并发编程系列(11)线程池底层原理架构剖析
本文详细解析了Java线程池的核心参数及其意义,包括核心线程数量(corePoolSize)、最大线程数量(maximumPoolSize)、线程空闲时间(keepAliveTime)、任务存储队列(workQueue)、线程工厂(threadFactory)及拒绝策略(handler)。此外,还介绍了四种常见的线程池:可缓存线程池(newCachedThreadPool)、定时调度线程池(newScheduledThreadPool)、单线程池(newSingleThreadExecutor)及固定长度线程池(newFixedThreadPool)。
|
16天前
|
Java
JAVA并发编程ReentrantLock核心原理剖析
本文介绍了Java并发编程中ReentrantLock的重要性和优势,详细解析了其原理及源码实现。ReentrantLock作为一种可重入锁,弥补了synchronized的不足,如支持公平锁与非公平锁、响应中断等。文章通过源码分析,展示了ReentrantLock如何基于AQS实现公平锁和非公平锁,并解释了两者的具体实现过程。
下一篇
无影云桌面