目录


连接池介绍

自定义连接池

JDBC Tomcat Pool

DBCP(DataBase Connection Pool)

使用配置文件来设置DBCP

C3P0

Druid


连接池介绍

  在说连接池之前,我们先想一个问题:程序要进行数据库操作,与数据库建立的是什么连接?开销怎么样?数据库是否可以同时支持上百万个连接?

  首先第一个问题:程序与数据库建立的是socket连接,走的是传输层,使用TCP。

  第二个问题:总开销 约等于 程序运行耗时 + 网络io + 数据库运行耗时。

  第三个问题:应该是不能同时支持上百万个连接,几千个应该就是上限了。

  看了上面三个问题,再提出一个问题:上面的问题中,我们可以优化哪一个环节?

  运维可以优化网络传输的问题;DBA可以优化数据库的运行性能。

  对于开发人员来说,我们可以优化第一个问题;首先,创建socket连接真的很耗时,主要的原因是因为建立TCP连接时有个3次握手,建立连接之后传输数据开销其实并不大。所以我们可以在这个角度上进行优化:尽量让程序与数据库建立几个连接,不要让程序频繁与数据库建立连接。

  为了业务的正常执行,线程需要与数据库进行交互,只建立几个数据库连接,好像不现实。

  我们可以换个方式来优化:创建固定数量的数据库的连接,这些数据库连接在Java中就是一个个对象而已,我们可以将这些对象存到容器中(比如List中),这个容器就叫做连接池。

  当有一个线程需要与数据库交互的时候,如果容器中还有数据库连接对象,那就从容器中取出一个连接对象,使用完之后,并不关闭数据库连接,而是将数据库连接对象放回容器,方便其他线程使用;如果线程需要与数据库交互时,容器中没有数据库连接对象了,那么这个线程他就阻塞一下,等待别的线程使用完连接之后归还,然后再使用别的线程归还的数据库连接。

  

自定义连接池

  自定义连接池的有个规范,需要实现DataSource接口,并且重写多个方法,但是主要重写一个无参的getConnection方法:

package cn.ganlixin.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger; import javax.sql.DataSource; /**
* 自定义的超简单的连接池,主要重写了DataSource接口中的getConnection方法,然后创建了归还连接的方法
*/
public class MyConnectionPool implements DataSource { // 创建一个同步的容器来保存数据库连接
private static List<Connection> connectionList =
Collections.synchronizedList(new LinkedList<Connection>()); // 设置建立数据库连接的最大数
private static final int MAX_CONNECTIONS = 50; // 编写静态初始化块,读取数据库配置文件,建立数据库连接,放入容器
static {
InputStream _is = MyConnectionPool.class.getClassLoader().getResourceAsStream("database.properties");
try {
Properties props = new Properties();
props.load(_is);
String driver = props.getProperty("jdbc.driver");
String url = props.getProperty("jdbc.url");
String username = props.getProperty("jdbc.username");
String password = props.getProperty("jdbc.password"); Class.forName(driver); // 创建多个连接,放入容器中
for (int i = 0; i < MAX_CONNECTIONS; i++) {
Connection conn = DriverManager.getConnection(url, username, password);
connectionList.add(conn);
System.out.println("创建第 " + (i+1) + " 个连接");
} } catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
} // 从容器中取出一个数据库连接对象
@Override
public Connection getConnection() throws SQLException { if (connectionList.size() > 0) {
// 如果容器中还有数据库连接对象,就将取出第一个对象,并将该对象从容器中删除
Connection conn = connectionList.remove(0);
System.out.println("使用了一个数据库连接, 容器中还剩下 " + connectionList.size() + " 个数据库连接");
return conn;
} return null;
} /**
* 归还数据库连接给容器,便于其他线程使用
* @param conn 要归还的数据库连接对象
*/
public void releaseConnection(Connection conn) {
connectionList.add(conn);
} @Override
public PrintWriter getLogWriter() throws SQLException { return null; } @Override
public void setLogWriter(PrintWriter out) throws SQLException { } @Override
public void setLoginTimeout(int seconds) throws SQLException { } @Override
public int getLoginTimeout() throws SQLException { return 0; } @Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; } @Override
public <T> T unwrap(Class<T> iface) throws SQLException { return null; } @Override
public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } @Override
public Connection getConnection(String username, String password) throws SQLException { return null; } }

  

  测试

package cn.ganlixin.test;

import java.sql.Connection;
import java.sql.SQLException; public class TestPool {
public static void main(String[] args) throws SQLException {
MyConnectionPool connectionPool = new MyConnectionPool(); // 获取连接池 for (int i = 0; i < 20; i++) {
// 获取连接
Connection connection = connectionPool.getConnection(); if (i % 3 == 0) { // 归还连接
connectionPool.releaseConnection(connection);
} System.out.println(connection);
}
}
}

  

JDBC Tomcat Pool

  tomcat服务器可以提供数据库连接池。我们可以将数据库连接池的配置保存在一个文件名为context.xml的文件中。

  context.xml可以放在项目下的webRoot/META-INF目录下,只对于本项目有效。

  context.xml可以放在tomcat服务器安装路径的conf目录下,针对所有项目都有效。

<?xml version="1.0" encoding="UTF-8"?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<Resource
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/test"
user="root"
password="123456"
name="tomcat_supported_pool"
auth="Container"
maxActive="50"
maxIdle="20"
maxWait="10000"
type="javax.sql.DataSource"
></Resource>
</Context>

  测试:

package lixin.gan.test;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException; import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.sql.DataSource; /**
* Servlet implementation class TestPool
*/
@WebServlet("/TestPool")
public class TestPool extends HttpServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8"); try {
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/tomcat_supported_pool"); Connection conn = ds.getConnection(); /* 进行数据库操作即可 */ } catch (NamingException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} }
}

    

DBCP(DataBase Connection Pool)

  需要下载commons-dbcp.jar、commons-pool.jar、commons-logging.jar。另外仍旧需要导入mysql的驱动包。

  下载网址(下载xxx-bin.zip即可):

    http://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi

    http://commons.apache.org/proper/commons-pool/download_pool.cgi

    http://commons.apache.org/proper/commons-logging/download_logging.cgi

    下载之后解压,将jar包添加到build path中。

  使用DBCP的示例:

package cn.ganlixin.test;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement; import org.apache.commons.dbcp2.BasicDataSource; public class TestDBCP {
public static void main(String[] args) throws SQLException { // 获取连接池
BasicDataSource dataSource = new BasicDataSource(); // 设置连接池相关信息
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setInitialSize(5);
dataSource.setMinIdle(2); // 获取数据库连接
Connection conn = dataSource.getConnection(); // 执行数据库操作
Statement stmt = conn.createStatement();
stmt.executeUpdate("update stu set age = 30 where id < 4"); // 这个close()方法被重写了,并不是关闭数据库连接,而是将连接归还连接池
conn.close(); }
}

  

使用配置文件来设置DBCP

  前面使用DBCP时,是在程序中手动指定连接信息,同样的,我们可以使用配置文件保存DBCP的连接信息。

  操作:在src下创建一个dbcp.properties文件,内容如下:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=root initialSize=20
maxIdle=10
minIdle=5
maxWait=10000

  

  使用DBCP

package cn.ganlixin.test;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Properties; import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory; public class TestPool {
public static void main(String[] args) throws Exception { BasicDataSourceFactory dataSourceFacoty = new BasicDataSourceFactory(); InputStream _is = TestPool.class.getClassLoader().getResourceAsStream("dbcp.properties");
Properties props = new Properties();
props.load(_is); // 获取连接池
BasicDataSource dataSource = dataSourceFacoty.createDataSource(props);
Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
stmt.executeUpdate("update stu set age = 30 where id < 4"); conn.close(); }
}

  

DBCP返回的数据库连接是包装类对象

  当我们从DBCP连接池获取的连接其实是一个经过包装之后的数据库连接对象,而不是原生的jdbc数据库连接对象:

package cn.ganlixin.test;

import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties; import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.apache.commons.dbcp2.DelegatingConnection; public class TestDBCP1 {
public static void main(String[] args) throws Exception { BasicDataSourceFactory dataSourceFacoty = new BasicDataSourceFactory(); InputStream _is = TestPool.class.getClassLoader().getResourceAsStream("dbcp.properties"); Properties props = new Properties();
props.load(_is); BasicDataSource dataSource = dataSourceFacoty.createDataSource(props); // 获取数据库连接
Connection conn = dataSource.getConnection(); System.out.println(conn.getClass().getName());
// org.apache.commons.dbcp2.PoolingDataSource$PoolGuardConnectionWrapper
// 通过DBCP连接池获得的是一个包装过后的连接池对象 // 可以通过下面的步骤获取原生的Connection对象
DelegatingConnection dc = (DelegatingConnection) conn;
Connection connection = dc.getInnermostDelegateInternal();
System.out.println(connection.getClass().getName());
// com.mysql.jdbc.JDBC4Connection }
}

  

C3P0

  C3P0也是一个数据库连接池的开源项目,他和DBCP功能类似,但是有一些区别:

  1、DBCP不会自动回收空闲连接的功能,而C3P0有这个功能。

  2、DBCP需要手动指定配置文件的路径以及文件明,而C3P0不需要(C3P0的配置文件指定路径和名称)。

  

  需要下载c3p0.jar,mchange-commons-java.jar,以及mysql的驱动包。

  http://central.maven.org/maven2/com/mchange/c3p0/0.9.5.4/c3p0-0.9.5.4.jar

  http://central.maven.org/maven2/com/mchange/mchange-commons-java/0.2.15/mchange-commons-java-0.2.15.jar

创建C3P0的配置文件

  C3P0的配置文件名为c3p0-config.xml,放在src目录下即可,配置文件的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">30</property>
<property name="maxIdleTime">60</property>
<property name="maxPoolSize">60</property>
<property name="minPoolSize">15</property>
</default-config> <!-- 可以指定两个数据库配置,一个线上环境,一个开发环境 -->
<named-config name="dev">
<property name=""></property>
<property name=""></property>
<property name=""></property>
<property name=""></property>
<property name=""></property>
<property name=""></property>
<property name=""></property>
<property name=""></property>
<property name=""></property>
</named-config>
</c3p0-config>

  

测试C3P0

package cn.ganlixin.test;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement; import com.mchange.v2.c3p0.ComboPooledDataSource; public class TestC3P0 {
public static void main(String[] args) throws SQLException { // 获取连接池
// 加载默认的数据库连接配置
// ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 使用c3p0配置文件中named-config里面name为dev的数据库配置
ComboPooledDataSource dataSource = new ComboPooledDataSource("dev"); // 获取数据库连接
Connection connection = dataSource.getConnection(); // 获取到数据库连接之后就可以进行各种操作了
// code // c3p0返回的数据库连接同样是包装类
System.out.println(connection);
// com.mchange.v2.c3p0.impl.NewProxyConnection@769c9116
// [wrapping: com.mysql.jdbc.JDBC4Connection@6aceb1a5] // 将数据库连接归还连接池
connection.close();
}
}

  

  

Druid

  Druid是alibaba开源的一个连接池项目;

  使用Druid,需要下载druid.jar以及mysql的驱动包;

  druid.jar的下载地址:http://central.maven.org/maven2/com/alibaba/druid/1.1.15/druid-1.1.15.jar

  github地址:https://github.com/alibaba/druid

 使用方法设置连接池信息

package cn.ganlixin.test;

import java.sql.SQLException;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection; public class TestDruid {
public static void main(String[] args) throws SQLException {
// 获取连接池对象
DruidDataSource dataSource = new DruidDataSource(); // 设置连接信息
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("root"); // 设置连接池的配置
dataSource.setInitialSize(20);
dataSource.setMaxActive(30);
dataSource.setMaxWait(1000);
dataSource.setMinIdle(10); // 获取连接(得到的不是原生的jdbc for mysql的连接对象)
DruidPooledConnection connection = dataSource.getConnection(); // 释放连接到连接池中
connection.close();
}
}

  

  使用properties配置文件的方式配置Druid

  配置Druid可以参考官方的示例:https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE

  在src下创建druid-config.properties(文件名随意),内容如下:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=root maxActive=10
initialSize=5
maxWait=10000
minIdle=5

  配置项和DBCP几乎一样。

  进行测试:

package cn.ganlixin.test;

import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties; import javax.sql.DataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; public class TestDruid2 {
public static void main(String[] args) throws Exception { InputStream _is = TestDruid2.class.getClassLoader().getResourceAsStream("druid-config.properties"); Properties props = new Properties();
props.load(_is); /**
读取配置文件,手动调用setter进行设置连接池
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(props.getProperty("driverClassName"));
.........
*/ // 利用工厂加载配置文件来配置连接池
DruidDataSourceFactory factory = new DruidDataSourceFactory();
DataSource dataSource = factory.createDataSource(props); // 获取数据库连接
Connection connection = dataSource.getConnection();
System.out.println(connection.getClass().getName()); connection.close();
}
}

  

Java 学习使用常见的开源连接池的更多相关文章

  1. Java学习笔记50(DBCP连接池)

    实际开发中,连接数据库是十分消耗资源的操作,但是,我们又需要频繁地连接数据库 这时候,为了提高效率,这里就会采用连接池技术: 连接池地通俗理解: 一个池里面放入很多的连接,需要哪一个取出来用即可,用完 ...

  2. 2、Java应用中常见的JDBC连接字符串(SQLite、MySQL、Oracle、Sybase、SQLServer、DB2)

    2.Java应用中常见的JDBC连接字符串 Java应用中连接数据库是不可或缺的,于是便整理一些可能用到的JDBC的jar包及其相匹配的URL,以备日后查阅. 1)SQLite Class.forNa ...

  3. Java开源连接池c3p0的基本用法

    前言:其实c3p0只是一个实现了javax.sql 接口 DataSource的一个工具集,使用c3p0可以帮我们管理宝贵的Connection资源,无须我们去创建连接(免去每次配置数据库驱动,url ...

  4. DBCP、C3P0、Proxool 、 BoneCP开源连接池的比《转》

     简介   使用评价  项目主页  DBCP DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序用使用 可以设置最大和最小连接,连接等待时 ...

  5. (转载)DBCP、C3P0、Proxool 、 BoneCP开源连接池的比较

    原文链接: http://blog.csdn.net/miclung/article/details/7231553    简介   使用评价  项目主页  DBCP DBCP是一个依赖Jakarta ...

  6. jdbc(1)(三)DBCP、C3P0、Proxool 、 BoneCP开源连接池的简介

     简介          使用评价  项目主页  DBCP DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序用使用 可以设置最大和最小连 ...

  7. 160629、 DBCP、C3P0、Proxool 、 BoneCP开源连接池的比较

       简介   使用评价  项目主页  DBCP DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序用使用 可以设置最大和最小连接,连接等 ...

  8. Java实战之04JavaWeb-05事务和连接池

    一.事务部分 1.事务的简介 做一件事情,这个一件事情中有多个组成单元,这个多个组成单元要不同时成功,要不同时失败.A账户转给B账户钱,将A账户转出钱的操作与B账户转入钱的操作绑定到一个事务中,要不这 ...

  9. 常见的DBCP连接池配置

    项目中使用mybatis出现一个问题,项目刚启动时,查询项目列表是ok的,过上一段时间之后,再次查询项目列表,查询失败,初步判断是因为mysql的连接问题,最后查阅资料,发现是连接池中的连接失效,导致 ...

随机推荐

  1. Hexo使用细节及各种问题

    解决markdown图片不显示(返回403 forbidden).添加本地图片无法显示.修改文章page模板.同时部署发布同步到多个仓库站点(Github.coding.gitee 码云) 图片不显示 ...

  2. February 19th, 2018 Week 8th Monday

    Love is blind, hard to find, difficult to get, and impossible to forget. 爱,很盲目,很难找,很难得,很难忘. It is al ...

  3. Glyphicons 字体图标

  4. java实现谷歌二步验证 (Google Authenticator)

    准备: 一个谷歌二步验证APP,  我用的是ios 身份宝 资料: 1.Google Authenticator 原理及Java实现   //主要参考 https://blog.csdn.net/li ...

  5. executequery要求已打开且可用的connection,连接的当前状态为已关闭

    问题: executequery要求已打开且可用的connection,连接的当前状态为已关闭 错误原因: 连接的当前状态为已关闭.或者只创建了Connection对象,没有调用Connection. ...

  6. golang 开发gui

    可能因为我电脑上的mingw下只有gcc,没有g++的原因,之前用walk和andlabs都不成功 最后用github上gxui的sample代码终于编译出来一个丑陋的GUI,但编译过程也提示了一堆类 ...

  7. [HAOI2018]苹果树

    嘟嘟嘟 这种计数大题就留给南方的计数神仙们做吧-- 刚开始我一直想枚举点,考虑新加一个点在根节点的左右子树,以及左右子树大小怎么分配,但是这样太难计算新的点带来的贡献了. 后来lba又提示我枚举边,考 ...

  8. [ZJOI2011]礼物

    嘟嘟嘟 正是因为有这样的数据范围,解法才比较暴力. 我们假设取出的长方体常和宽相等,即\(a * a * b\).这样我们每次换两条边相等,搞三次就行. 那么对于第\(k\)层中的第\((i, j)\ ...

  9. Scala主构造器参数是否升级为成员与是否有get/set

    1:主构造器前面添加val/var 关键字则升级为类成员,否则只是构造器中的一个参数而已. 2:private 修饰get/set方法权限,private var/val 成员变量,则有get/set ...

  10. Thymeleaf3语法详解

    每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code   Thymeleaf是Spring boot推荐使用的模版引擎,除此之外常见的还有F ...