您的位置:首页 > 运维架构 > Tomcat

数据库连接池c3p0和dbcp和tomcat-dbcp

2017-05-22 17:37 441 查看
jdbc(Java DataBase Connection):

是应用程序与数据库沟通的桥梁, 即Java语言通过JDBC技术访问数据库。

一般来说,Java应用程序访问数据库的过程是:

  ①装载数据库驱动程序;

  ②通过JDBC建立数据库连接;

  ③访问数据库,执行SQL语句;

  ④断开数据库连接。

jdbc是一种数据库访问技术,具有简单易用的优点。但在WEB应用程序开发中,存在很多问题

  首先、每一次WEB请求都要建立一次数据库连接,建立连接是个费时的活动,而且过程中系统还要分配内存资源。在高并发情况下,这种频繁的对数据库连接操作势必会降低响应速度,严重的可能导致服务器崩溃;

  其次,对于每次的数据库连接,使用完都得断开,如若连接未能关闭,将会导致数据库系统内存泄漏。最终将不得不重启数据库。

  再者,这种连接方式不能控制被创建的连接数,会将系统资源毫无保留的分配出去,连接数过多,也会导致内存泄漏,导致服务器崩溃。  

  由上面的分析可以看出,问题就出在对数据库资源连接的低效管理。由此,我们在此基础上对JDBC进行优化,提出了数据库连接池(connection pool)

  资源池(resoure pool)主要作用有俩个:控制数量、资源重利用。

连接池的分配与释放:

  已经创建的连接都放入List中去统一管理。每当用户请求一个连接时,系统检查这个List中有没有可以分配的连接。如果有就把那个最合适的连接分配给他;如果没有就抛出一个异常给用户,List中连接是否可以被分配由一个线程来专门管理。

连接池的配置与维护:

  采取设置最小连接数(minConnection)和最大连接数(maxConnection)等参数来控制连接池中的连接,来使系统的性能最佳。最小连接数是系统启动时连接池所创建的连接数。如果创建过多,则系统启动就慢,但创建后系统的响应速度会很快;如果创建过少,则系统启动的很快,响应起来却慢。这样,可以在开发时,设置较小的最小连接数,开发起来会快,而在系统实际使用时设置较大的,因为这样对访问客户来说速度会快些。最大连接数是连接池中允许连接的最大数目,具体设置多少,要看系统的访问量,可通过软件需求上得到。

  如何确保连接池中的最小连接数呢?有动态和静态两种策略。动态即每隔一定时间就对连接池进行检测,如果发现连接数量小于最小连接数,则补充相应数量的新连接,以保证连接池的正常运转。静态是发现空闲连接不够时再去检查。  

使用数据库连接池的优势和其工作原理:

  1、连接池的优势:

连接池的主要优点有以下三个方面。

  一、减少连接创建时间。连接池中的连接是已准备好的、可重复使用的,获取后可以直接访问数据库,因此减少了连接创建的次数和时间。

  二、简化的编程模式。当使用连接池时,每一个单独的线程能够像创建一个自己的JDBC连接一样操作,允许用户直接使用JDBC编程技术。

  三、控制资源的使用。如果不使用连接池,每次访问数据库都需要创建一个连接,这样系统的稳定性受系统连接需求影响很大,很容易产生资源浪费和高负载异常。连接池能够使性能最大化,将资源利用控制在一定的水平之下。连接池能控制池中的连接数量,增强了系统在大量用户应用时的稳定性。

  2、连接池的工作原理

  连接池的工作原理主要由三部分组成,分别为连接池的建立、连接池中连接的使用管理、连接池的关闭。

  一、连接池的建立。一般在系统初始化时,连接池会根据系统配置建立,并在池中创建了几个连接对象,以便使用时能从连接池中获取。连接池中的连接不能随意创建和关闭,这样避免了连接随意建立和关闭造成的系统开销。Java中提供了很多容器类可以方便的构建连接池,例如Vector、Stack等。

  二、连接池的管理。连接池管理策略是连接池机制的核心,连接池内连接的分配和释放对系统的性能有很大的影响。其管理策略是:

  >>当客户请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给客户使用;如果没有空闲连接,则查看当前所开的连接数是否已经达到最大连接数,如果没达到就重新创建一个连接给请求的客户;如果达到就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户。

  >>当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就从连接池中删除该连接,否则保留为其他客户服务。该策略保证了数据库连接的有效复用,避免频繁的建立、释放连接所带来的系统资源开销。

  >>连接池的关闭。当应用程序退出时,关闭连接池中所有的连接,释放连接池相关的资源,该过程正好与创建相反。

  

几种常用的数据库连接池

一、DBCP (Database Connection Pool)

  所需jar包:commons-dbcp.jar、commons-pool.jar、commons-collections-3.1.jar

  配置

  

<!-- 配置dbcp数据源 -->
<bean id="dataSource2" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- 池启动时创建的连接数量 -->
<property name="initialSize" value="5"/>
<!-- 同一时间可以从池分配的最多连接数量。设置为0时表示无限制。 -->
<property name="maxActive" value="30"/>
<!-- 池里不会被释放的最多空闲连接数量。设置为0时表示无限制。 -->
<property name="maxIdle" value="20"/>
<!-- 在不新建连接的条件下,池中保持空闲的最少连接数。 -->
<property name="minIdle" value="3"/>
<!-- 设置自动回收超时连接 -->
<property name="removeAbandoned" value="true" />
<!-- 自动回收超时时间(以秒数为单位) -->
<property name="removeAbandonedTimeout" value="200"/>
<!-- 设置在自动回收超时连接的时候打印连接的超时错误  -->
<property name="logAbandoned" value="true"/>
<!-- 等待超时以毫秒为单位,在抛出异常之前,池等待连接被回收的最长时间(当没有可用连接时)。设置为-1表示无限等待。  -->
<property name="maxWait" value="100"/>
</bean>


二、C3P0

  所需jar包:c3p0-0.9.2.1.jar、mchange-commons-java-0.2.3.4.jar

  配置

  

<!-- 配置c3p0数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize" value="100" />
<!--连接池中保留的最小连接数。-->
<property name="minPoolSize" value="1" />
<!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
<property name="initialPoolSize" value="10" />
<!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime" value="30" />
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement" value="5" />
<!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements
属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
<property name="maxStatements" value="0" />

<!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod" value="60" />

<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts" value="30" />

<!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
<property name="breakAfterAcquireFailure" value="true" />

<!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的
时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
等方法来提升连接测试的性能。Default: false -->
<property name="testConnectionOnCheckout"  value="false" />
</bean>


三、tomcat 自带的tomcat jdbc pool

  Tomcat默认使用的是DBCP数据库连接池,其实从本质上讲,Tomcat是利用Apache Commons DBCP来实现的,只不过把特定的功能集成到了tomcat-dbcp.jar包中。

  Tomcat 在 7.0 以前的版本都是使用 commons-dbcp 做为连接池的实现,但是 dbcp 饱受诟病,原因有:

  1、dbcp 是单线程的,为了保证线程安全会锁整个连接池

  2、dbcp 性能不佳

  3、dbcp 太复杂,超过 60 个类

  4、dbcp 使用静态接口,在 JDK 1.6 编译有问题

  5、dbcp 发展滞后

为此,Tomcat 从 7.0 开始引入一个新的模块:Tomcat jdbc pool

  1、tomcat jdbc pool 近乎兼容 dbcp ,性能更高

  2、异步方式获取连接

  3、tomcat jdbc pool 是 tomcat 的一个模块,基于 tomcat JULI,使用 Tomcat 的日志框架

  4、使用 javax.sql.PooledConnection 接口获取连接

  5、支持高并发应用环境

  6、超简单,核心文件只有8个,比 c3p0 还

  7、更好的空闲连接处理机制

  8、支持 JMX、支持 XA Connection

  9、tomcat jdbc pool 可在 Tomcat 中直接使用,也可以在独立的应用中使用。

  

配置方法:

方法一、在Tomcat\conf目录下的context.xml文件中Context标签结尾前配置如下内容:

<!--配置oracle数据库的连接池-->
<Resource name="jdbc/oracleds"
author="Container"
type="javax.sql.DataSource"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="scott"
password="tiger"
driverClassName="oracle.jdbc.dirver.OracleDriver"
url="jdbc:oracle:thin:@127.0.0.1:1521:ora9" />

<!--配置mysql数据库的连接池,
需要做的额外步骤是将mysql的Java驱动类放到tomcat的lib目录下
maxIdle 连接池中最多可空闲maxIdle个连接
minIdle 连接池中最少空闲maxIdle个连接
initialSize 初始化连接数目
maxWait 连接池中连接用完时,新的请求等待时间,毫秒
username 数据库用户名
password 数据库密码
-->
<Resource name="jdbc/mysqlds"
auth="Container"
type="javax.sql.DataSource"
username="root"
password="root"
maxIdle="30"
maxWait="10000"
maxActive="100"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/db_blog" />


配置好后需要注意的两个步骤:

1.将对应数据库的驱动类放到tomcat的lib目录下

2.重新启动tomcat服务器,让配置生效

在web应用程序的web.xml中设置数据源参考,如下:

在web-app节点中加入下面内容

<resource-ref>
<description>mysql数据库连接池</description>
<!-- 参考数据源名字,同Tomcat中配置的Resource节点中name属性值"jdbc/mysqlds"一致 -->
<res-ref-name>jdbc/mysqlds</res-ref-name>
<!-- 资源类型 -->
<res-type>javax.sql.DataSource</res-type>
<!-- 权限 -->
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>


在Web应用中使用数据源

try {
//初始化查找命名空间
Context ctx = new InitialContext();
//参数java:/comp/env为固定路径
Context envContext = (Context)ctx.lookup("java:/comp/env");
//参数jdbc/mysqlds为数据源和JNDI绑定的名字
DataSource ds = (DataSource)envContext.lookup("jdbc/mysqlds");
Connection conn = ds.getConnection();
conn.close();
out.println("<span style='color:red;'>JNDI测试成功<span>");
} cat
c063
ch (NamingException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}


方法二、在Tomcat的conf/server.xml中配置虚拟目录时配置

在配置虚拟目录时,也就是在配置conf下面的server.xml时,在context标签内添加池配置.在说该方法之前,先说一下,如何用tomcat配置虚拟目录。在tomcat\conf下server.xml中找到

<Host name="localhost"  appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
</Host>


在其中添加:

<Context path="/website" docBase="F:/myweb" reloadable="true"></Context>


注意:

docBase要改成你的项目目录。

path为虚拟路径,访问时的路径,注意:一定要加“/” debug建议设置为0

reloadable设置为true。

这样重新启动tomcat

实例中如下配置

<Context path="/website" docBase="D:/program files/Tomcat/apache-tomcat-6.0.33/webapps/iblog.war" reloadable="true">
</Context>


接下来添加池配置,如下

<!--配置虚拟目录-->
<Context path="/website" docBase="D:/program files/Tomcat/apache-tomcat-6.0.33/webapps/iblog.war" reloadable="true">
<Resource name="jdbc/mysqlds"
auth="Container"
type="javax.sql.DataSource"
username="root"
password="root"
maxIdle="30"
maxWait="10000"
maxActive="100"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/db_blog"
/>
</Context>


方法三、在Web项目中的META-INF目录下新建一个文件context.xml,写入配置

注意:是META-INF目录下,不是WEB-INF目录下

<?xml version='1.0' encoding='utf-8'?>
<Context>
<Resource name="jdbc/mysqlds"
auth="Container"
type="javax.sql.DataSource"
username="root"
password="root"
maxIdle="30"
maxWait="10000"
maxActive="100"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/db_blog"
logAbandoned="true" />
</Context>


方法四、在Tomcat的conf/server.xml中配置

打开tomcat的conf/server.xml文件,找到GlobalNamingResources节点,默认的内容如下

<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>


在该节点中加入相关的池配置信息,如下

<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />

<!--配置mysql数据库的连接池,
需要做的额外步骤是将mysql的Java驱动类放到tomcat的lib目录下
-->
<Resource name="jdbc/mysqlds"
auth="Container"
type="javax.sql.DataSource"
username="root"
password="root"
maxIdle="30"
maxWait="10000"
maxActive="100"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/db_blog" />
</GlobalNamingResources>


在tomcat的conf/context.xml文件中的节点中加入如下内容

<ResourceLink name="jdbc/mysqlds" global="jdbc/mysqlds" type="javax.sql.DataSource"/>


然后在web项目中的WEB-INF目录下的web.xml中配置

<resource-ref>
<description>mysql数据库连接池</description>
<!-- 参考数据源名字,同Tomcat中配置的Resource节点中name属性值"jdbc/mysqlds"一致 -->
<res-ref-name>jdbc/mysqlds</res-ref-name>
<!-- 资源类型 -->
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>


同样配置好后,需要重新启动服务器,让配置生效.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  连接池 c3p0 jdbc dbcp tomcat