C3P0链接池解析java
1,链接池的原理和意义
无论什么样的链接池其核心意义都是一致的,就是为一个项目建立链接对象,保存在池中待用。每次访问时从池中
获取已经存在的链接,使用完毕后,再返回池中。从而减小了建立链接和销毁链接而浪费的系统资源。本文会分析
目前经常使用链接池之一C3P0。
2,C3P0简单配置
c3p0链接池做为咱们开发中最为经常使用的链接池之一使用起来是很是简单的。本文将从原理角度来分析一下 C3P0连
接池的主要架构。
通常只须要配置如下参数便可:
一般状况下,咱们还会跟本地配置文件properties或者本地xml文件相结合的方式进行操做,以加强代码的灵活
性。
3,核心类
C3P0链接池主要核心类有如下几个:
ComboPooledDataSource:主要负责链接池的配置和获取池中的链接
C3P0PooledConnectionPoolManager:大内总管的角色。
负责生命周期以及生命周期所须要的一些参数。
好比:AdminTaskTimer定时检测和全局的线程池C3P0PoolConnectionPool:
表示物理链接池,自己的业务逻辑相对于比较简单,主要核心是经过代理ResourcePool来实现逻辑的。
BasicResourcePool:
是BasicResourcePool这个接口的实现类,是大内总管 C3P0PooledConnectionPoolManager的手下。
大内总管管池子,而BasicResourcePool是管池中链接的生命周期。
至关于大内中长春宫,宁寿宫等每个宫的管事。
String driverClass = "com.mysql.jdbc.Driver";
String jdbcURL = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "";
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass(driverClass);
cpds.setJdbcUrl(jdbcURL);
cpds.setUser(user);
cpds.setPassword(password);
须要用的时候再得到其中的链接便可。
Connection conn = cpds.getConnection();
BasicResourcePool.Manager:
是BasicResourcePool的一个助手,协助一块儿管理链接池中的链接。
在BasicResourcePool中有几个任务须要注意:
1,建立链接ScatteredAcquireTask
2,销毁链接RemoveTask
3,检测链接是否过时CullTask
4,检测链接是否空闲CheckIdleResourcesTask
4,初始化特色
C3P0链接池在初始化的时候并非在建立的时候直接建立并进行初始化的,链接池采起了一种“懒初始化”的思
想。那么何为懒初始化呢?
本身自己不会不会主动初始化,而是会等到第一个链接请求进来以后它才会初始化。而那个触发点就是:
当代码执行到这里,即获取到一个链接时,才会进行初始化保证了资源的有效利用。
5,建立链接从而下降系统资源消耗
众所周知,使用链接池中的链接是为了下降系统资源消耗,那么到底是为何呢?
首先数据库实际上是一个管理系统,以MySQL为例,MySQL是一个数据库管理系统,区分服务端和客户端,MySQL
指的是这个总体管理系统,因此想要实际的把数据存入到表中,须要经历如下过程。
创建TCP链接,而后经过三次握手协议发送与相应;其次客户端须要进行帐户验证,服务器返回确认;用户验证
后,须要传输相关链接变量如是否自动提交事务的设置等。
因此总而言之,操做数据以前,必定会有屡次数据的交互,而后才能执行真正的执行CURD的sql语句。
链接池真正的下降的是以上的这些步骤,当须要对数据库进行操做时,直接获取已经存在的,就减小了资源的消
耗。
预先创建多个数据库链接对象,存入到池中。当有客户端进行请求的时候,取出一个链接为当前客户端的请求而操
做数据库,当该客户端请求操做完毕时,将请求放回链接池里。一直没有关闭。
6,链接池下降消耗的原理图解
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.getConnection();
北京市昌平区建材城西路金燕龙办公楼一层 电话:400-618-9090
若是没有链接池,那么访问者跟数据库之间每次都建立一个链接,用完再销毁。
若是用了链接池,就不会本身建立,而是从池子中拿,用完再进行归还。
7,入口类ComboPooledDataSource
在进行初始化建立的时候,会有池子的入口类,就是ComboPooledDataSource。其中gettConnection方法是在
AbstractPoolBackedDataSource类中实现。
其中PooledConnection是javax.sql下的一个接口。针对于这个链接的执行者对象,结果集对象和链接对象对被
pooledconnection管理。而c3p0实现是NewPooledConnection。
8,BasicResourcePool类
8.1,主要核心代码:
其中timeout表示链接溢出时间。
查看池中是否有未使用的connection,若是有就返回,除此以外,还须要判断链接是否空闲经过timeout判断链接
是否过时,若是没有最大数,就生成一个,或者就等待。
8.2,主要核心代码:
AbstractPoolBackedDataSource类的getConnection方法以下:
public Connection getConnection() throwsSQLException{
PooledConnection pc = getPoolManager().getPool().checkoutPooledConnection();
returnpc.getConnection();
} O
bject resc = prelimCheckoutResource(timeout);
booleanrefurb = attemptRefurbishResourceOnCheckout(resc);
获得链接后,检测链接的可用性。 若是链接可用,接着判断链接是否处于管理中,若是不在就再调用本方法获取一
个,若是在,就返回本链接。
8.3,添加链接
获取链接时由BasicResourcePool类中的prelimCheckoutResource方法触发,调用过程以下:
1,BasicResourcePool类prelimCheckoutResource方法当可用链接数为0时调用recheckResizePool方法。
2,echeckResizePool方法判断须要扩容则调用expandPool方法。expandPool方法使用线程池调用AcquireTask
进行扩容。
3,AcquireTask调用mgr.acquireResource方法获取链接,若是链接池里的链接未到最大数量将获取的链接加入管
理和未使用的list中,不然销毁链接。
8.4,回收链接
由close方法触发。调用过程以下:
1,C3P0PooledConnectionPool类,的ConnectionEventListenerImpl监听器类的connectionClosed方法被触发。
2,判断同步仍是异步的(默认是同步)。若是是异步,那么就采用线程池来进行处理回收,若是是同步,那么就
进行直接调用BasicResourcePool类的checkinResource方法对链接进行回收,此处的回收并非销毁,而是归
还。
9,死锁机制
在C3P0中有不少任务都是采起多线程进行处理的。好比添加连接或者是回收链接。一旦有这种相似于生产者消费
者的多线程任务,那么就必需要进行死锁判断,不然会进入无线等待状态。
该机制的是由ThreadPoolAsynchronousRunner类的子类DeadlockDetector来执行具体的操做的。、
DeadlockDetector类继承了TimerTask类,由其中的Timer来调用DeadlockDetecto运行。DeadlockDetector类中
有两个属性:LinkedListlast 和 LinkedListcurrent。
这两个LinkedList集合放的是等待执行的任务。根据他的属性名字就很轻易理解,last是上次检测时待执行的任务
而current是本次检测时要执行的任务,当pendingTasks不为空且current.equals( last)时认为死锁发生。当一旦确
认死锁发生了,那么会把当前任务交给ThreadPerTaskAsynchronousRunner类来处理,这个类会启用新的线程
DispatchThread来处理当前的任务队列。
总结:
链接池能够在访问数据库时下降系统消耗。因此不论是什么项目都一定会有链接池的存在。
链接池基本使用很是的简单,经过一些简单的配置便可,可是想要真正把链接池原理理解,建议等用熟以后,闲暇
之余再进行研究。mysql