数据源(连接池)的机制

上次说到为什么使用数据库连接池,因为连接池是一个系统的闸口,那么连接池本身的工作原理是什么呢,下面结合A家的开源数据库连接池druid()一起分析一下。

数据源和连接池的区别

首先连接池是一个宽泛的概念,我们都知道连接池都是有初始大小,也上限的(为什么要有上限,因为怕被拖垮),最大闲置时间等等这些只是“池”的一些配置。那既然是数据库连接池,那么必须有要跟数据库打交道,而世上数据库太多了,每个数据库都有自己的驱动(JDBC),同时还需配置数据库地址,账号密码,等等这些都扔给连接池去维护那就太不优雅了。所以把整个跟数据库驱动注册、连接、配置管理等一系列的处理封装称之为数据源,其实官方的接口只认数据源的,看一下java源码(方法注释略去):


package javax.sql;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Wrapper;

/**
 * 

A factory for connections to the physical data source that this * {@code DataSource} object represents. An alternative to the * {@code DriverManager} facility, a {@code DataSource} object * is the preferred means of getting a connection. An object that implements * the {@code DataSource} interface will typically be * registered with a naming service based on the * Java™ Naming and Directory (JNDI) API. *

* The {@code DataSource} interface is implemented by a driver vendor. * There are three types of implementations: *

    *
  1. Basic implementation -- produces a standard {@code Connection} * object *
  2. Connection pooling implementation -- produces a {@code Connection} * object that will automatically participate in connection pooling. This * implementation works with a middle-tier connection pooling manager. *
  3. Distributed transaction implementation -- produces a * {@code Connection} object that may be used for distributed * transactions and almost always participates in connection pooling. * This implementation works with a middle-tier * transaction manager and almost always with a connection * pooling manager. *
*

* A {@code DataSource} object has properties that can be modified * when necessary. For example, if the data source is moved to a different * server, the property for the server can be changed. The benefit is that * because the data source's properties can be changed, any code accessing * that data source does not need to be changed. *

* A driver that is accessed via a {@code DataSource} object does not * register itself with the {@code DriverManager}. Rather, a * {@code DataSource} object is retrieved though a lookup operation * and then used to create a {@code Connection} object. With a basic * implementation, the connection obtained through a {@code DataSource} * object is identical to a connection obtained through the * {@code DriverManager} facility. *

* An implementation of {@code DataSource} must include a public no-arg * constructor. * * @since 1.4 */ public interface DataSource extends CommonDataSource, Wrapper { Connection getConnection() throws SQLException; Connection getConnection(String username, String password) throws SQLException; }

看到这边,可以清楚到知道:其实连接池只是数据源的一种比较常见的实现方式,具体如下:
1.基本实现、直接返回连接
2.连接池实现,自动从维护中的池里取出连接
3.分布式事务实现,但是同样也是会用到连接池,只是有中间事务管理

第1种实现比较简单,直接使用JDBC请求生成连接返回即可;第3种分布式比较复杂,不在本文主旨讨论范围内;所以重点聊一下第二种。

数据源怎么运作

首先我们看一下一般情况下怎么使用druid数据源,比如注册到spring中


<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
  destroy-method="close" init-method="init">
  <property name="url" value="${dbconf.url}" />
  <property name="username" value="${dbconf.username}" />
  <property name="password" value="${dbconf.password}" />
  <property name="driverClassName" value="${dbconf.driverClass}" />
  <property name="initialSize" value="5" />
  <property name="maxActive" value="20" />
  <property name="maxWait" value="60000" />
  <property name="removeAbandoned" value="true" />
  <property name="removeAbandonedTimeout" value="180" />
  <property name="poolPreparedStatements" value="true" />
  <property name="maxPoolPreparedStatementPerConnectionSize"
    value="20" />
  <property name="connectionProperties"
    value="druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000" />
</bean>

启动类DruidDataSource,想必大家也猜到了,init初始方法传入配置参数,可以看到仍然是依赖具体驱动(各个数据库的JDBC)。同时也实现了DataSource,内部使用了线程池、并发控制等一系列处理逻辑,代码太多就不贴出来了,就放一个官方的字符图诠释吧:

screen-shot-2016-09-14-at-%e4%b8%8a%e5%8d%881-26-07

这就是整个线程池实现的一个逻辑谱图,当然除此之外druid数据源还包括监控、日志、防SQL注入等其他模块,具体问题可以继续深入研究。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>