目录


连接池介绍

自定义连接池

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. 让EntityFramework.Extended支持MySql

    EF:Entity Framework EFEL:Entity Framework Extended Library EFEL5.0时代是不支持MySql的,现在升级到6.0之后,已经支持MySql了 ...

  2. 12.scrapy框架之递归解析和post请求

    今日概要 递归爬取解析多页页面数据 scrapy核心组件工作流程 scrapy的post请求发送 今日详情 1.递归爬取解析多页页面数据 - 需求:将糗事百科所有页码的作者和段子内容数据进行爬取切持久 ...

  3. Why do Kafka consumers connect to zookeeper, and producers get metadata from brokers?

    Why do Kafka consumers connect to zookeeper, and producers get metadata from brokers? Ask Question u ...

  4. CF 1110 D/E

    CF 1110 D. Jongmah 题目大意:给你​\(n\)个瓷砖,每块瓷砖上有一个数字​\(a_i,(1\leq a_i\leq m)\).你可以将三个有连续数字​\((比如3,4,5)\)的瓷 ...

  5. Scrapy 框架 CrawlSpider 全站数据爬取

    CrawlSpider 全站数据爬取 创建 crawlSpider 爬虫文件 scrapy genspider -t crawl chouti www.xxx.com import scrapy fr ...

  6. centos7下安装docker(15.7容器跨主机网络---calico)

    Calico是一个纯三层的虚拟网络方案,Calico为每个容器分配一个IP,每个host都是router,把不同host的容器连接起来.与vxlan不同的是:calico不对数据包进行封装,不需要NA ...

  7. docker 8 docker的镜像命令

    先回顾一下容器.存储.镜像三者之间的关系. 我们知道docker的logo是一条大鲸鱼背上驮着集装箱.那我们对应到docker如下: 1)蓝色的大海里面------->宿主机系统比如我笔记本wi ...

  8. RabbitMQ详解(二)------消息通信的概念

    PS:近期在南宁出差,工作比较忙,所以更新会比较慢. 说到消息通信,可能我们首先会想到的是邮箱,QQ,微信,短信等等这些通信方式,这些通信方式都有发送者,接收者,还有一个中间存储离线消息的容器.但是这 ...

  9. element-ui中 table表格hover 修改背景色

    增加样式级别就行啦   .el-table--enable-row-hover .el-table__body tr:hover>td{ background-color: #212e3e !i ...

  10. C# 相关面试试题简单的总结

    最近一个搞NET开发的朋友离职了,想让我给他找点关于NET的相关面试题,准备抱一下佛脚,迎接新的挑战. 我赶紧找到以前检索的各种宝典,试题,今天梳理一下关于NET的基础知识点. 1.面向对象语言的三大 ...