一、什么是数据库连接池?
官方:数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。
个人理解:创建数据库连接是一个很耗时的操作,也容易对数据库造成安全隐患。所以,在程序初始化的时候,集中创建多个数据库连接,并把他们集中管理,供程序使用,可以保证较快的数据库读写速度,还更加安全可靠。
二、数据库连接池的运行机制
(1) 程序初始化时创建连接池
(2) 使用时向连接池申请可用连接
(3) 使用完毕,将连接返还给连接池
(4) 程序退出时,断开所有连接,并释放资源
三、数据库连接池的使用
作为开源的数据库连接池,C3P0是一个优秀的连接池,性能也十分可靠。
Druid 连接池简介
Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。
同时Druid不仅仅是一个数据库连接池,它包括四个部分:
Druid是一个JDBC组件,它包括三个部分:
基于Filter-Chain模式的插件体系。
DruidDataSource 高效可管理的数据库连接池。
SQLParser
Druid的功能
1、替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。
2、可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。
3、数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。
4、SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
5、扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩展插件。
使用原因
原先项目使用的是C3P0连接池,在项目发布使用一段时间后发现c3p0 连接池访问数据库的时候创建连接会在oralce的lisenter.log 日志文件记录。
经过一段时间观察发现oralce每6秒会在lisenter.log日志记录一次,我们设置的最小连接是20,所以oracle每次会在日志记录20条。随着时间越长日志文件越来越大,当日志文件达到4个G的时候会导致oracle死掉。 经过不断调整参数配置还是无法得到解决方案,最后选择使用阿里Druid连接池试试,Druid默认最小连接2个,配置好后发布观察日志发现只在创建的时候在日志里面记录了2条记录。没有像C3P0那样每6秒记录一次导致日志文件越来越大。
lisenter.log 日志截图
Druid使用
1. Druid.jar包
druid-1.1.22.jar 1.1.4
首先到http://sourceforge.net/projects/c3p0/下载相应的jar包,总共三个,如下图所示。
其次将jar包导入到工程当中,然后就可以使用c3p0和Druid了。
c3p0和Druid连接池示例代码如下(代码就不分文件了最基础的连接就不放代码了,直接第二种连接池技术放一起,不需要另一种连接池就直接注释掉就好):
JDBCUtils.java文件
package testConnection;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.DbUtils;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* Demo class 使用的c3p0、Druid连接技术
*
* @author: HuMonster
* @date: 2020/8/10
*/
public class JDBCUtils {
/** 使用配置文件实现c3p0连接数据库 方式二 */
public static Connection getConnection() throws SQLException {
ComboPooledDataSource cpds = new ComboPooledDataSource("c3p0");
Connection conn = cpds.getConnection();
System.out.println(conn);
return conn;
}
/** 使用Druid数据库连接技术连接 方式二 */
private static DataSource source;
static {
try {
Properties props = new Properties();
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
props.load(is);
source = DruidDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection2() throws Exception {
Connection conn = source.getConnection();
return conn;
}
public static void closeResourse(Connection conn, Statement ps, ResultSet rs) {
// /**
// * 第一种关闭方法
// */
// try {
// DbUtils.close(conn);
// } catch (SQLException e) {
// e.printStackTrace();
// }
//
//
// /**
// * 第二种关闭方法
// */
// try {
// if (ps != null) ps.close();
// } catch (Exception e) {
// e.printStackTrace();
// }
/** 第三种关闭方法 调用dbutils.jar中提供DbUtils工具类,实现资源的关闭的方法 */
DbUtils.closeQuietly(conn);
DbUtils.closeQuietly(ps);
DbUtils.closeQuietly(rs);
}
}
c3p0-config.xml连接池的配置文件实现
<?xml version='1.0' encoding='UTF-8'?>
<c3p0-config>
<default-config>
<!-- 提供获取连接的4个基本信息 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/~~数据库名~~ </property>
<property name="user">~~用户名~~ </property>
<property name="password">~~密码~~ </property>
<!--进行数据连接池管理的基本信息 -->
<!-- 当数据连接池中的连接数不够时,c3p0一次性向数据库申请的连接数 -->
<property name="acquireIncrement">5</property>
<!--c3p0数据库连接池中初始化时的连接-->
<property name="initialPoolSize">10</property>
<!--c3p0数据库连接池维护数最少的连接数-->
<property name="minPoolSize">10</property>
<!--c3p0数据库连接池维护的最多的连接数-->
<property name="maxPoolSize">100</property>
<!--c3p0数据库连接池维护的最多Statements的连接数-->
<property name="maxStatements">50</property>
<!--每个连接中可以最多使用的Statements个数-->
<property name="maxStatementsPerConnection">5</property>
</default-config>
<named-config name="c3p0"></named-config>
</c3p0-config>
druid.properties 德鲁伊连接池文件配置文件(配置文件中文件信息不能留空格)
username=~~数据库用户名~~
password=~~密码~~
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/info_schema
initialSize=10
maxActive=10
最后附上实现连接池的连接的多种方法(增删改查)DBUtilsConnectionTest.java
package testConnection;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;
import java.sql.Connection;
import java.util.Map;
/**
* Demo class 基于两种连接方法对数据库操作的测试
*
* @author: HuMonster
* @date: 2020/8/10
*/
public class DBUtilsConnectionTest {
/** 基于阿里提供的dbutils对数据库进行的增加操作 */
@Test
public void testTnsert() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection2();
String sql = "insert into t_admin(admin_name,admin_pwd)values(?,?)";
int insertCount = runner.update(conn, sql, "超人1", "888");
System.out.println("添加了" + insertCount + "条记录");
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResourse(conn, null, null);
}
}
/** MapHandle:是ResoultSetHandler接口的实现类,对应表中的一条记录 将字段相应的值作为map中的key和value */
@Test
public void testQuery() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection2();
String sql = "select log_amount,log_type,created from t_log where log_id = ?";
MapHandler handler = new MapHandler();
Map<String, Object> map = runner.query(conn, sql, handler, 50);
System.out.println(map);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResourse(conn, null, null);
}
}
/** 查询日志表的全部数据条数 c3p0 */
@Test
public void testQuery1() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection();
String sql = "select count(*) from t_log";
ScalarHandler handler = new ScalarHandler();
Long count = (Long) runner.query(conn, sql, handler);
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResourse(conn, null, null);
}
}
/** 查询最大数值的log—id */
@Test
public void testQuery2() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection2();
String sql = "select max(log_id) from t_log";
ScalarHandler handler = new ScalarHandler();
int maxId = (int) runner.query(conn, sql, handler);
System.out.println(maxId);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResourse(conn, null, null);
}
}
@Test
public void testQuery3() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection2();
String sql = "select log_id,log_type,log_amount,created from t_log where log_id = ?";
ScalarHandler handler = new ScalarHandler();
int maxId = (int) runner.query(conn, sql, handler, 70);
System.out.println(maxId);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResourse(conn, null, null);
}
}
}