之前的工具类DBUtil暴露的问题

用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、服务器挂掉。

解决方法-数据库连接池

 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响 到程序的性能指标.数据库连接池正式针对这个问题提出来的.数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。

最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费.

最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作

编写数据库连接池

编写连接池需实现java.sql.DataSource接口

在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。

实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。

当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。Collection保证将自己返回到 LinkedList中是此处编程的难点。

首先是 数据库配置文件database.properties

url=jdbc:mysql://localhost:3306/libweb
driver=com.mysql.jdbc.Driver
user=root
password=
initSize=5

其次是自己写的数据库连接池类 DBpool

package dbex.mysql;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties; import javax.sql.DataSource; import dbex.DBUtil; /**
*
* @ClassName: DBpool
* @Description: 自己编写数据库连接池
* @author penny
* @date 2017年12月1日 上午10:55:31
*
*/
public class DBpool implements DataSource { // 使用lindedlist集合存放数据库连接,可供频繁读取
private static LinkedList<Connection> pools = new LinkedList<Connection>();
static {
// 静态代码库中加载数据库配置文件database.xml
InputStream in = DBpool.class
.getResourceAsStream("../../database.properties");
Properties pro = new Properties();
try {
// 静态代码快加载驱动
pro.load(in);
Class.forName(pro.getProperty("driver"));
int initSize = Integer.parseInt(pro.getProperty("initSize"));
for (int i = 0; i < initSize; i++) {
Connection conn = DriverManager.getConnection(
pro.getProperty("url"), pro.getProperty("user"),
pro.getProperty("password"));
System.out.println(DBpool.class.toString() + ":数据库连接池初始化第"
+ (i + 1) + "个连接=" + conn);
pools.add(conn);
}
} catch (Exception e) {
// TODO: handle exception
}
} /**
* 获取数据库连接池的连接
*/
@Override
public Connection getConnection() throws SQLException {
// 如果数据库连接池有空余连接
if (pools.size() > 0) {
final Connection conn = pools.removeFirst();// 从连接池取出一个连接对象
System.out.println(DBpool.class.toString() + ":数据库连接池可用连接数="
+ pools.size());
/**
* 使用动态代理技术构建连接池中的connection
*/
return (Connection) Proxy.newProxyInstance(DBpool.class.getClassLoader(), conn.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,Object[] obj) throws Throwable {
if (!method.getName().equals("close")) {
return method.invoke(conn, obj);
} else {
pools.add(conn);// 如果调用close()方法就需要把连接回收到连接池
System.out.println(DBpool.class.toString()
+ ":数据库连接池回收一个连接=" + conn
+ ",连接池可用连接数=" + pools.size());
return null;
}
}
}); } else {
throw new RuntimeException("对不起,数据库忙,没有可用连接!");
} } @Override
public Connection getConnection(String arg0, String arg1)
throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
} @Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
} @Override
public void setLogWriter(PrintWriter arg0) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int arg0) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public boolean isWrapperFor(Class<?> arg0) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public <T> T unwrap(Class<T> arg0) throws SQLException {
// TODO Auto-generated method stub
return null;
}
}

最后是基于数据库连接池的数据库连接工具类

package dbex;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import dbex.mysql.DBpool; /**
*
* @ClassName: DBUtil2
* @Description: 使用了数据库连接池的数据库工具类
* @author penny
* @date 2017年12月1日 下午10:30:41
*
*/
public class DBUtil2 { private static DBpool pools = new DBpool();
/**
*
* @Title: getConnection
* @Description: 获取一个数据库连接池的连接对象conn
* @param @return Connection() conn
* @param @throws SQLException
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
return pools.getConnection();
}
/***
*
* @Title: release
* @Description: 关闭并释放资源
* @param @param conn 连接对象
* @param @param ppst 预处理语句
* @param @param rs 返回结果集
* @throws
*/
public void release(Connection conn,PreparedStatement ppst,ResultSet rs){
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException("关闭数据库 Connection异常");
}
}
if(ppst!=null){
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException("关闭数据库 PreparedStatement异常");
}
}
if(rs!=null){
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException("关闭数据库 ResultSet异常");
}
}
}
public static void main(String[] args) {
System.out.println("<====================测试使用数据库连接池的工具类===================>");
DBUtil2 db2 = new DBUtil2(); try {
System.out.println(db2.getConnection());
System.out.println(db2.getConnection());
System.out.println(db2.getConnection());
System.out.println(db2.getConnection());
Connection conn=db2.getConnection();
System.out.println(conn);
db2.release(conn, null, null);
System.out.println(db2.getConnection());
// db2.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

测试效果

总结

首先感谢孤傲沧浪大哥总结和分享,在这里学习了

1 基础知识反射,以及动态代理模式的熟练使用

2 研究下其他开源的数据库连接池工具DBCP C3P0 或者代码

JDBC 学习复习6 学习与编写数据库连接池的更多相关文章

  1. JDBC 学习复习7 学习 Apache 开源DBCP 数据源

    DBCP(DataBase connection pool),数据库连接池.是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件.单独使用dbcp需要2个包:comm ...

  2. JDBC 学习笔记(三)—— 数据源(数据库连接池):DBCP数据源、C3P0 数据源以及自定义数据源技术

    本文目录:        1.应用程序直接获取连接的缺点(图解)        2.使用数据库连接池优化程序性能(图解)        3.可扩展增强某个类方法的功能的三种方式        4.自定 ...

  3. 【Java EE 学习 16 上】【dbcp数据库连接池】【c3p0数据库连接池】

    一.回顾之前使用的动态代理的方式实现的数据库连接池: 代码: package day16.utils; import java.io.IOException; import java.lang.ref ...

  4. java web学习总结(十六) -------------------数据库连接池

    一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大 ...

  5. JavaWeb学习总结(十三)--数据库连接池

    一.数据库连接池的概念 用池来管理Connection,这可以重复使用Connection.有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象.当使用完Co ...

  6. javaweb学习总结(三十九)——数据库连接池

    一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大 ...

  7. JavaWeb学习(三十)———— 数据库连接池

    一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大 ...

  8. mybatis学习三 数据库连接池技术

    1.在内存中开辟一块空间,存放多个数据库连接对象.就是Connection的多个实例2. 连接池技术有很多,c3p0,dbcp,druid,以及JDBC Tomcat Pool, JDBC Tomca ...

  9. JavaWeb学习笔记(十七)—— 数据库连接池

    一.数据库连接池概述 1.1 为什么使用数据库连接池 如果用户每次请求都向数据库获得连接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建1 ...

随机推荐

  1. 2019.06.17课件:[洛谷P1310]表达式的值 题解

    P1310 表达式的值 题目描述 给你一个带括号的布尔表达式,其中+表示或操作|,*表示与操作&,先算*再算+.但是待操作的数字(布尔值)不输入. 求能使最终整个式子的值为0的方案数. 题外话 ...

  2. Docs-.NET-C#-指南-语言参考-预处理器指令:#undef(C# 参考)

    ylbtech-Docs-.NET-C#-指南-语言参考-预处理器指令:#undef(C# 参考) 1.返回顶部 1. #undef(C# 参考) 2018/06/30 #undef 允许你定义一个符 ...

  3. Android:导入所需的系统jar包到Android studio

    1. 修改对于的AIDL文件,根据编译信息获知所需的jar包. mmm /frameworks/base/ show commands > log.txt 2>&1 out/tar ...

  4. EasyUI实现图片的上传后与其他文本框的提交以及DataGrid中图片的展示

    图片即文件,在jsp中文件上传很简单,一个type为file的input,一个form指定enctype为multipart/form-data,通过post提交到后台利用apache的commons ...

  5. 《海会圣贤》高清字幕版(由香港佛陀教育协会发布DVD恭敬转成)

    常念阿彌陀佛 2015-09-22 视频(建议WIFI下收看)时长72分钟 https://v.qq.com/x/page/f0166amk57h.html 香港佛陀教育协会发布DVD   DVD+高 ...

  6. DN创建

    1. 参考采购订单创建DN : BAPI_OUTB_DELIVERY_CREATE_STO FUNCTION zmmfm0202. *"--------------------------- ...

  7. 浏览器最小显示12px字体的解决方法

    今天做打印标签,发现浏览器最小字体限制了12px,标签那么小,12px随便几个字就给占满了: 最后通过  transform:scale(1,0.8) 搞定: 这个属性允许将元素移动.压缩.旋转:这里 ...

  8. LeetCode_121. Best Time to Buy and Sell Stock

    121. Best Time to Buy and Sell Stock Easy Say you have an array for which the ith element is the pri ...

  9. 建立django项目的完整流程

    简单的django登录项目 1.首先建立工程,建立工程请参照:https://www.cnblogs.com/effortsing/p/10394511.html 2.在Firstdjango工程项目 ...

  10. shell数组编程

    .数组定义 [chengmo@centos5 ~]$ a=( ) [chengmo@centos5 ~]$ echo $a 一对括号表示是数组,数组元素用“空格”符号分割开. .数组读取与赋值 得到长 ...