JDBC 学习复习6 学习与编写数据库连接池
之前的工具类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 学习与编写数据库连接池的更多相关文章
- JDBC 学习复习7  学习 Apache 开源DBCP 数据源
		
DBCP(DataBase connection pool),数据库连接池.是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件.单独使用dbcp需要2个包:comm ...
 - JDBC 学习笔记(三)—— 数据源(数据库连接池):DBCP数据源、C3P0 数据源以及自定义数据源技术
		
本文目录: 1.应用程序直接获取连接的缺点(图解) 2.使用数据库连接池优化程序性能(图解) 3.可扩展增强某个类方法的功能的三种方式 4.自定 ...
 - 【Java EE 学习 16 上】【dbcp数据库连接池】【c3p0数据库连接池】
		
一.回顾之前使用的动态代理的方式实现的数据库连接池: 代码: package day16.utils; import java.io.IOException; import java.lang.ref ...
 - java web学习总结(十六) -------------------数据库连接池
		
一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大 ...
 - JavaWeb学习总结(十三)--数据库连接池
		
一.数据库连接池的概念 用池来管理Connection,这可以重复使用Connection.有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象.当使用完Co ...
 - javaweb学习总结(三十九)——数据库连接池
		
一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大 ...
 - JavaWeb学习(三十)———— 数据库连接池
		
一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大 ...
 - mybatis学习三  数据库连接池技术
		
1.在内存中开辟一块空间,存放多个数据库连接对象.就是Connection的多个实例2. 连接池技术有很多,c3p0,dbcp,druid,以及JDBC Tomcat Pool, JDBC Tomca ...
 - JavaWeb学习笔记(十七)—— 数据库连接池
		
一.数据库连接池概述 1.1 为什么使用数据库连接池 如果用户每次请求都向数据库获得连接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建1 ...
 
随机推荐
- GDPR全文翻译(二)
			
第三节 数据保护影响评估以及事先咨询 第35条 数据保护影响评估 1.鉴于一种数据处理方式,尤其是使用新技术进行数据处理,统筹考虑处理过程的性质.范围.内容和目的,(不难得知)这很可能对自然人权利和自 ...
 - zblog文件大小超出,上传成功但插入不了
			
在zblogphp时,经常会遇到需要上传2m以上的文件或图片,这个时候就需要修改默认上传文件的大小了.看了很多地方的文章都解决不了,后面在麒麟杰博客找到相关解决办法. 工具/原料 zblogp ...
 - flutter的生命周期
			
大致可以看成三个阶段 初始化(插入渲染树) 状态改变(在渲染树中存在) 销毁(从渲染树种移除) initState 当插入渲染树的时候调用,这个函数在生命周期中只调用一次.这里可以做一些初始化工作,比 ...
 - 03--STL算法(常用算法)
			
一:常用的查找算法 (一)adjacent_find():邻接查找 在iterator对标识元素范围内,查找一对相邻重复元素,找到则返回指向这对元素的第一个元素的迭代器.否则返回past-the-en ...
 - Cas(01)——简介
			
Cas的全称是Centeral Authentication Service,是对单点登录SSO(Single Sign On)的一种实现.其由Cas Server和Cas Client两部分组成,C ...
 - 股票PE的应用
			
投资股票前,需要先分析公司,然后做估值.最后拿这估值对比现在它的现价,如果现价远低于估值,那就买入,因为这时候相当于打折价. 分析要怎么分析,估值要怎么估值 就像拿不同的旋头去维修不同的电器是一样的原 ...
 - 最新 贝壳找房java校招面经 (含整理过的面试题大全)
			
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.贝壳找房等10家互联网公司的校招Offer,因为某些自身原因最终选择了贝壳找房.6.7月主要是做系统复习.项目复盘.Leet ...
 - 在vue中使用axios发送post请求,参数方式
			
由于后台接收的参数格式为FormData格式, 在axios中参数格式默认为, 在传参数前,将原先官方提供的格式 改为如下: axios({ url: '../../../room/listRoomP ...
 - execl文件读取封装
			
前言:做自动化常用的公共方法 注:第一次使用记得先 pip install xlrd 模块import xlrd class ReadExecl(): def __init__(self,filena ...
 - Lnamp的高级网站架构+动静分离+反向代理
			
Lnamp的架构 环境: 图上面是5台服务器 192.168.1.116 是nginx负载均衡+动静分离 192.168.1.117:linux+apache+php 192.168.1.118:li ...
 
			
		