C3P0 与 DBCP 数据库连接池使用和比较

7 篇文章 0 订阅

博主声明:

转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。

本文首发于此   博主威威喵  |  博客主页https://blog.csdn.net/smile_running

   我们知道JDBC是连接数据库的基石,JDBC为Java访问数据库提供了简单、易用的功能特性。通常我们使用JDBC获取数据库连接时,只需要配置几步必要的参数就可以,虽然我们获取了连接,但是这个连接的获取却来自不易。

    为什么说来之不易呢,也许你会觉得,我的代码连接数据库都是非常快的啊,叮,它就能给我查询出来想要的结果。这是没错的,通常这是在我们本地调试的情况下,这个状态下连接数据库几乎没有并发连接情况,这个时候是最理想的状态。但一个服务器不可能仅在本地使用,所以就有以下这种情况。

    如果我们将数据库发布到云服务器上,现在有成千上万的用户在同时访问数据库,如果你的服务器不是特别高端,或者说在一个配置不咋样的服务器上来同时访问,每次访问数据库 Connection 就会被加载到内存中,当在庞大的并发量下,你的服务器就会boom(奔溃了)。如果不限制并发连接的数量,那系统就会毫无顾及的一直将资源消耗下去,直到它内存溢出。

例如下面获取数据库连接的代码:

	@Deprecated
	public static Connection getConnection() throws Exception {
		String driver = null;
		String jdbcUrl = null;
		String user = null;
		String password = null;

		InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
		Properties properties = new Properties();
		properties.load(inputStream);
		driver = properties.getProperty("driver");
		jdbcUrl = properties.getProperty("jdbcUrl");
		user = properties.getProperty("user");
		password = properties.getProperty("password");
		Class.forName(driver);
		return (Connection) DriverManager.getConnection(jdbcUrl, user, password);
	}
  •  数据库连接池

    就如上面所说的那样,这种实现方式去获取连接,每次我们一关闭连接又得重新来获取,显得有点鸡肋,而且无法控制并发数量,一般在企业开发中是不会用这种方式去获取数据库连接的。所以,我们就引入了数据库连接池(Connection Pool)的概念。

    什么是数据库连接池呢?看名词的字面意思,就是存储数据库连接的一个池子,和线程池的概念类似。一个存放数据库连接的池子,它应该有大小(连接数量)、进出水量(连接的并发量)、不能溢出(连接最大数量)、不能干涸(连接最小数量)等等属性。

关于数据库连接池的一些官方介绍:

  • 数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
  • 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个
  • 数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。

一、优点

  1. 资源重用,由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增加了系统运行环境的平稳性。
  2. 更快的系统反应速度,数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间
  3. 新的资源分配手段,对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用独占所有的数据库资源
  4. 统一的连接管理,避免数据库连接泄露 在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露

二、开源工具

    数据库连接池既然如此重要,那么一些开源组织也已经为我们准备好了两种开源的数据库连接池,我们不需要自己写数据库连接池,拿来就可以使用。这两种分别是:DBCP 、C3P0

1、DBCP连接池

    DBCP(database connection pool),是 Apache 软件基金组织下的开源连接池实现,该连接池依赖该组织下的另一个开源系统:Common-pool

    DBCP与JDBC一样,提供两种可连接的方式,一种是通过代码的方式(局限性比较大)。

	@Test
	public void dbcpTest() {
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql://localhost:3306/person");
		dataSource.setUsername("root");
		dataSource.setPassword("123456");

		// 指定初始化的连接数
		dataSource.setInitialSize(50);
		// 设置允许被同时连接的最大数,意味着同一时刻可以并发连接的最大数
		dataSource.setMaxTotal(20);
		// 设置向数据库连接时延迟的最长时间,超过该时间则连接失败
		dataSource.setMaxWaitMillis(5 * 1000);
		// 设置空闲时最小能保持的连接数,在连接关闭时,多余的连接数将在连接池中销毁
		dataSource.setMinIdle(5);

		try {
			Connection conn = dataSource.getConnection();
			System.out.println(conn);
			System.out.println("连接成功了");
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

    另一种则是通过配置文件的方式:dbcp.properties

    通过代码加载配置文件并连接

	@Test
	public void dbcpTest2() throws Exception {
		Properties properties = new Properties();
		InputStream inStream = this.getClass().getClassLoader().getResourceAsStream("dbcp.properties");
		properties.load(inStream);
		BasicDataSource dataSource = new BasicDataSourceFactory().createDataSource(properties);

		Connection conn = dataSource.getConnection();
		System.out.println(conn);
		System.out.println("连接成功了");
	}

2、C3P0连接池

    C3P0,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等,这个被推荐使用,它需要的库如下:

通过代码连接:

	@Test
	public void c3p0Test() throws Exception{
		ComboPooledDataSource cpds = new ComboPooledDataSource();
		cpds.setDriverClass("com.mysql.jdbc.Driver");
		cpds.setJdbcUrl("jdbc:mysql://localhost:3306/person");
		cpds.setUser("root");
		cpds.setPassword("123456");
		Connection conn = cpds.getConnection();
		System.out.println(conn);
		System.out.println("连接成功了");
	}

    C3P0比较特殊,它可以通过XML文件来配置连接属性,并且规定为:c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>

	<named-config name="jdbcConfig">

		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/person</property>
		<property name="user">root</property>
		<property name="password">123456</property>

		<!-- 当连接数量用尽时,可定期的增量数 -->
		<property name="acquireIncrement">10</property>
		<!-- 数据库初始化时,需要初始化连接池中连接的数量 -->
		<property name="initialPoolSize">100</property>
		<!-- 连接池的最小连接数 -->
		<property name="minPoolSize">10</property>
		<!-- 连接池的最大连接数 -->
		<property name="maxPoolSize">200</property>
		<!-- 连接池中 Statement 的最大个数 -->
		<property name="maxStatements">20</property>
		<!-- 连接池中每个连接可以同时使用的 Statement 的个数 -->
		<property name="maxStatementsPerConnection">5</property>
	</named-config>
</c3p0-config>

    连接代码:

	@Test
	public void c3p0Test2() throws Exception{
		DataSource dataSource = new ComboPooledDataSource("jdbcConfig");
		Connection conn = dataSource.getConnection();
		System.out.println(conn);
		System.out.println("连接成功了");
	}

3、区别

    从代码上看,相比之下c3p0的代码更加精简,而且是被推荐于使用,大多第三方开源框架都是基于c3p0来建立连接的。从两个开源库本质特点上来说,它们应用于不同的场景,所以它们拥有各自的特点。

  •     dbcp:无法自动回收空闲的连接,提供最大的连接数,如果连接数超出,则会断开连接。
  •     c3p0,可以自动回收空闲的连接,提供最大的空闲时间,如果超出最大的连接时间,则会断开连接。
用jdbc开发项目的工具包,采用数据库连接池c3p0 恶意脚本过滤器,采用‘装饰者设计模式’增强类功能~~,过滤恶意脚本 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package cn.secondteam.utils; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 恶意脚本字符过滤器 * @author Administrator * */ public class CharFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; chain.doFilter((ServletRequest) Proxy.newProxyInstance(CharFilter.class.getClassLoader(),request.getClass().getInterfaces(), new InvocationHandler(){ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("getParameter")){ return formatHTML((String)method.invoke(request, args)); } return method.invoke(request, args); } }), res); } public void init(FilterConfig filterConfig) throws ServletException { } private String formatHTML(String str) { if(str==null){ return null; } str = str.replaceAll("<sc", "<sc"); str = str.replaceAll("</sc", ">/sc"); //str = str.replaceAll(">", ">"); return str; } public void destroy() { // TODO Auto-generated method stub } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值