之前的工具类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. 8.3 Customizing Git - Git Hooks

    https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks https://github.com/git/git/blob/master/temp ...

  2. SVN分支创建与合并

    SVN分支 一个branch是某个development line(通常是主线也即trunk)的一个拷贝,branch存在的意义在于,在不干扰trunk的情况下,和trunk并行开发,待开发结束后合并 ...

  3. SQL-W3School-函数:SQL LEN() 函数

    ylbtech-SQL-W3School-函数:SQL LEN() 函数 1.返回顶部 1. LEN() 函数 LEN 函数返回文本字段中值的长度. SQL LEN() 语法 SELECT LEN(c ...

  4. Oracle存在则更新,不存在则插入应用-merge

    转: Oracle存在则更新,不存在则插入应用-merge 2017年01月11日 14:15:26 周星猩 阅读数 11354更多 分类专栏: Oracle   版权声明:本文为博主原创文章,遵循C ...

  5. 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_11-SpringSecurityOauth2研究-JWT研究-JWT介绍

    3.6 JWT研究 3.6.1 JWT介绍 在介绍JWT之前先看一下传统校验令牌的方法,如下图: 问题: 传统授权方法的问题是用户每次请求资源服务,资源服务都需要携带令牌访问认证服务去校验令牌的合法性 ...

  6. 使用Tomcat搭建基于域名的虚拟机

    Tomcat搭建基于域名的虚拟主机,实际就是实现了同一个Tomcat部署多个项目(网站/应用程序).端口可以使用同一个,也可以不同. (1).在tomcat的conf文件夹下存在Tomcat的配置文件 ...

  7. spark在windows的配置

    在spark-env.cmd添加一行 FOR /F %%i IN ('hadoop classpath') DO @set SPARK_DIST_CLASSPATH=%%i 修改:log4j.prop ...

  8. Masonry详解

    - (void)viewDidLoad { [super viewDidLoad]; //1.view1 居中显示 UIView *view1 = [[UIView alloc]init]; view ...

  9. react 点击事件

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. Python3类和实例之获取对象信息

    当我们拿到一个对象的引用时,如何知道这个对象是什么类型,有哪些方法呢 使用type() 判断对象类型使用type()函数 基本类型都可以用type()判断 <class 'int'> &g ...