一 平时使用jdbc弊端
普通的JDBC数据库连接使用 DriverManager 来获取,每次向数据库建立连接的时候都要将 Connection 加载到内存中,再验证用户名和密码(得花费0.05s~1s的时间)。
需要数据库连接的时候,就向数据库要求一个,执行完成后再断开连接。这样的方式将会消耗大量的资源和时间。数据库的连接资源并没有得到很好的重复利用.若同时有几百人甚至几千人在线,频繁的进行数据库连接操作将占用很多的系统资源,严重的甚至会造成服务器的崩溃。
对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将导致重启数据库。
这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃
二 数据库连接池
1 诞生
(为解决传统开发中的数据库连接问题可以采用数据库连接池技术)
数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
2 优点
资源重用:由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增加了系统运行环境的平稳性。
更快的系统反应速度:数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间
新的资源分配手段对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置实现某一应用最大可用数据库连接数的限制避免某一应用独占所有的数据库资源.
统一的连接管理,避免数据库连接泄露在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。
ps:(以上文字摘抄网上老鸟的,嘿嘿描述太多就懒得写了,我还是总结实现原理在这就树下乘凉了哈哈!!!)
三 常用的连接池
1 DBCP
2 c3p0
四 自定义实现(了解思想即可)
1 实现思路
就是在连接池初始化的时候存入一定数量的连接,用的时候通过方法获取,不用的时候归还连接即可.
2 规范(oracle公司规定接口,驱动供应商实现):
所有的连接池必须实现一个接口 javax.sql.DataSource接口
查看api:(DataSource)
获取连接方法:
Connection getConnection()
我们发现只有连接的方法 没有归还的方法归还连接的方法就是以前的释放资源的方法.调用connection.close();
3 JdbcUtil 工具类:
package jdbc;
import java.sql.*;
import java.util.ResourceBundle;
/**
* jdbc 操作的工具封装
* Create by SunnyDay on 2018/11/10
* 连接 释放资源的步骤都是相同的 可以抽取
*/
public class JdbcUtil {
private static ResourceBundle resourceBundle = ResourceBundle.getBundle("jdbc");
//1 获得连接
public static Connection getConnection() {
Connection connection = null;
try {
Class.forName(resourceBundle.getString("driverclass"));
connection = DriverManager.getConnection(resourceBundle.getString("url"), resourceBundle.getString("user"), resourceBundle.getString("password"));
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
// 2释放资源
public static void releaseResource(Connection conn, Statement statement, ResultSet resultSet) {
closeResultSet(resultSet);
closeStatement(statement);
closeConnnection(conn);
}
//关闭连接
private static void closeConnnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
// 关闭结果集合
private static void closeResultSet(ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 关闭预编译状态
private static void closeStatement(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
4 MyDataSource(自定义的 未完全实现 借鉴一下思路即可)
package jdbc;
import java.sql.Connection;
import java.util.LinkedList;
/**
* Create by SunnyDay on 2018/11/10
* 自定义简单连接池
* <p>
* 思路:
* 1 首先搞个获取连接,归还连接的方法
* 2 连接池就是在初始化的时候存放连接 我们想到可以使用静态代码块 或者构造
* 3 初始化的时候存放连接 存放想到使用容器(根据增删,与查找区别)
*/
public class MyDataSource {
private static LinkedList<Connection> pool = new LinkedList<>();
static {
// 初始化的时候放入3个连接
for (int i = 0; i < 3; i++) {
Connection connection = JdbcUtil.getConnection();
pool.addLast(connection);
}
}
/**
* 从连接池中获取连接
*/
public static Connection getConnection() {
// 获取的时候需要判断连接是否为null 空的时候再添加几个入队列
if (pool.isEmpty()) {
for (int i = 0; i < 3; i++) {
Connection connection = JdbcUtil.getConnection();
pool.addLast(connection);
}
}
return pool.removeFirst();// 先进的先出来 队列思想
}
/**
* 归还连接方法
*
*/
public static void addBack(Connection conn) {
// 只需要将连接放入到集合的最后即可
pool.addLast(conn);
/* 此时是有弊端的,如果忘记了归还我们就 开始关闭资源 这种现象不好
我们想 如果关闭资源的时候会先自动掉此方法就好了
实现:
1 用继承(实现) 子类可以拿到父类东西 切可以修改(重写)
弊端:需要父类
2 装饰着模式(静态代理)
3 动态代理
使用装饰者:(实现步骤)
1 装饰者 和被装饰者同时实现同一个接口 或者继承同一个类
2 装饰者中要有被装饰着的引用
3 对需要增强的方发进行增强()
4 对不需要增强的方法调用原来的方法()
*/
}
}
小结: 终于又总结完了一张,通过本篇掌握jdbc连接池相关的作用及其思想,以及装饰者模式就行。
参考:dbcp c3p0其dbutils总结