一、概念
官方:数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。
二、原理
传统统链接:
一般来说,Java应用程序访问数据库的过程是:
(1)装载数据库驱动程序;
(2)通过JDBC建立数据库连接;
(3)访问数据库,执行SQL语句;
(4)断开数据库连接。
数据库连接池的机制:
(1)程序初始化时创建连接池
(2)使用时向连接池申请可用连接
(3)使用完毕,将连接返还给连接池
(4)程序退出时,断开所有连接,并释放资源
简单介绍连接池的工作原理:
连接池技术的核心思想是连接复用,连接池的工作原理主要由三部分组成,分别为连接池的建立、连接池中连接的使用管理、连接池的关闭。
三、各种数据库连接池介绍
Java中常用的数据库连接池有:DBCP 、C3P0、BoneCP、Proxool、DDConnectionBroker、DBPool、XAPool、Primrose、SmartPool、MiniConnectionPoolManager及Druid等。
这里只介绍其中几种:
1.DBCP
dbcp连接池可以设置最大和最小连接,连接等待时间等基本功能。
具体配置如下:
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/database
username=admin
password=admin
配置参数详解:
注意JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
MaxActive:连接池的最大数据库连接数。设为0表示无限制。maxActive是最大激活连接数,这里取值为20,表示同时最多有20个数据库连接。
maxIdle: 连接池中最多可空闲maxIdle个连接,maxIdle是最大的空闲连接数,这里取值为20,表示即使没有数据库连接时依然可以保持20空闲的连接,而不被清除,随时处于待命状态。
minIdle:连接池中最少空闲maxIdle个连接。
initialSize:初始化连接数目。
maxWait:连接池中连接用完时,新的请求等待时间,毫秒 MaxWait是最大等待秒钟数,这里取值-1,表示无限等待,直到超时为止,也可取值9000,表示9秒后超时。
maxIdle:最大空闲数,数据库连接的最大空闲时间。超过空闲时间,数据库连接将被标记为不可用,然后被释放。设为0表示无限制。
defaultAutoCommit:指定由连接池所创建的连接的自动提交(auto-commit)状态,取ture/false。
defaultReadOnly:driver default 指定由连接池所创建的连接的只读(read-only)状态。
defaultTransactionIsolation:定由连接池所创建的连接的事务级别(TransactionIsolation),可以是NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=REPEATABLE_READ。
//JdbcTemplate---Spring对数据库的操作在jdbc上面做了深层次的封装,使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中。
//JdbcTemplate中用到默认连接池就是DBCP
private JdbcTemplate getJdbcTempalte(DoctorMoveDatasource db){
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(db.getDriver());
dataSource.setUrl(db.getUrl());
dataSource.setUsername(db.getUsername());
dataSource.setPassword(db.getPassword());
dataSource.setMaxActive(2);
dataSource.setMaxIdle(2);
dataSource.setDefaultAutoCommit(false);
dataSource.setInitialSize(2);
dataSource.setTimeBetweenEvictionRunsMillis(600000L);
dataSource.setMinEvictableIdleTimeMillis(1800000L);
return new JdbcTemplate(dataSource);
}
拓展:
JdbcTemplate主要提供以下五类方法:
execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
query方法及queryForXXX方法:用于执行查询相关语句;
call方法:用于执行存储过程、函数相关语句。
2.C3P0
c3p0是另外一个开源的连接池,在业界也是比较有名的,这个连接池可以设置最大和最小连接,连接等待时间等,基本功能都有。这个连接池的配置参见附件压缩包中的:c3p0.xml。
使用评价:在具体项目应用中,发现此连接池的持续运行的稳定性相当不错,在大并发量的压力下稳定性也有一定保证,此外不提供连接池监控。
(1)C3P0 数据库连接池技术实现步骤
- 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar (注意:因为是连接数据库,不要忘记导入数据库驱动 jar 包)
- 定义配置文件:
名称:c3p0.properties 或 c3p0-config.xml(名字必须为这两个中一个,因为会自动加载配置文件)
路径:直接将文件放置 src 目录下即可。 - 创建核心对象 数据库连接池对象 ComboPooledDataSource
- 获取连接:getConnection()
代码实现:
public static void main(String[] args) throws SQLException {
// 创建数据库连接对象
DataSource ds = new ComboPooledDataSource(); // 会自动去加载配置文件
//获取连接对象
Connection conn = ds.getConnection();
// 打印连接对象
System.out.println(conn);
// 归还对象
conn.close();
}
(2)导入的 jar 包
C3P0-0.9.5.2.jar
mchange-commons-java-0.2.12.jar
mysql-connecter-java-5.1.40-bin.jar
(3)配置文件
c3p0-config.xml 配置文件
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/bookstore</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<!--初始化连接的数量-->
<property name="initialPoolSize">5</property>
<!--最大的连接数量-->
<property name="maxPoolSize">10</property>
<!--超时时间-->
<property name="checkoutTimeout">3000</property>
</default-config>
<!--通过指定的名字来获取连接的数据库-->
<named-config name="otherc3p0">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/bookstore</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
注意:在配置文件中可以连接多个不同的数据库,用 声明即可,到时候使用 name 属性来调用即可,如果没有指定 name,那么调用默认的数据库。
public static void main(String[] args) throws SQLException {
// 创建数据库连接对象
//DataSource ds = new ComboPooledDataSource(""); //连接默认的数据库
DataSource ds = new ComboPooledDataSource("otherc3p0"); //连接 name=otherc3p0数据库
//2 获取连接
Connection conn = ds.getConnection();
Statement stmt = conn.createStatement();
// 3.归还连接
conn.close();
}
3.proxool
4.Druid
(1)Druid数据库连接池技术实现步骤
- 导入 jar 包druid-1.0.9.jar
- 定义配置文件
名称:是properties 形式的,需要手动加载
路径:可以放在任意目录下(建议放在src目录下) - 加载配置文件 properties
- 获取数据连接池对象:通过工厂来获取 DruidDataSourceFactory
- 获取连接:getConnection
- 归还连接:close()
代码实现:
public class DruidDemo1 {
public static void main(String[] args) throws Exception {
//1.导入jar包
//2.定义配置文件
//3.加载配置文件
Properties prop = new Properties();
InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
prop.load(is);
//4.获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(prop);
//5.获取连接
Connection conn = ds.getConnection();
System.out.println(conn);
// 6.归还连接
conn.close();
}
}
(2)导入的 jar 包
druid-1.0.9.jar
(3)配置文件
druid.properties 文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/bookstore
username=root
password=root
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 延迟时间
maxWait=3000
(4)Druid 连接池的工具类
可以将数据库连接池封装成一个工具类,这样在获取的连接的时候,直接拿来用即可,不用再创建连接池,更加方便。
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* Druid 连接池的工具类
*/
public class JDBCUtils {
// 1.定义成员变量
private static DataSource ds;
static {
//加载配置文件
Properties pro = new Properties();
try {
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
// 2 获取datasource
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
/**
* 释放资源
*/
public static void close(Statement stmt, Connection conn) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 获取连接池方法
*/
public static DataSource getDataSource() {
return ds;
}
}