一、数据库连接池
数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而再不是重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
1、数据库连接池的基本是实现
它的实现途径:
编写JdbcPool implements java.sql.DataSource类
● 静态初始化
● getConnection()
● release()
2、Connection
1) 编写Connection的子类,此方法理论上可以解决,但是没有可操作性,因为基本无法实现对Connection对象的初始化工作
2) 采用装饰模式
装饰模式解决方案
用包装设计模式对connnction的close方法进行增强
1.写一个类实现与被增强对象相同的接口
2.在类中定义一个变量记住被增强对象
3.在类中定义一个构造函数,接收被增强对象
4.覆盖想增强的方法
5.对于不想增强的方法,直接调用目标对象(被增强对象)的方法
3、动态代理模式
代理模式的作用:
为其他对象提供一种代理以控制对这个对象的访问。(在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用)
● 抽象角色:声明真实对象和代理对象的公共接口。
● 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真是对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。 同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
● 真实角色:代理角色所代表的真实对象,是我们要真正要引用的对象。
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1) InvocationHandler接口,是代理实例的调用处理程序实现的接口。 它只有一个方法:invoke(Object proxy, Method method, Object[] args)。我们需要在实现InvocationHandler接口的具体类中的invoke方法内,编写代理行为的具体逻辑。然后将这个InvocationHandler对象传递给Proxy类中生成一个动态的代理对象。
(2) Proxy 类,提供用于创建动态代理类和实例的静态方法
二、DBCP
DBCP(DataBase connection pool),数据库连接池。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。单独使用dbcp需要3个包:
common-dbcp.jar,
common-pool.jar
,common-collections.jar
由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。
操作步骤:
1、赋值jar包及dbconfig.properties文件
2、修改配置文件
3、 修改DBManager文件
a) 静态初始化块,加载配置文件
b) DataSource ds = BasicDataSourceFactory.createDataSource(prop);
c) 修改getConnection()
3、在数据库操作中任然使用DBManager的getConnection和release方法即可
三、C3P0
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
C3P0使用步骤:
1、 复制jar文件
c3p0-0.9.2-pre1.jar
mchange-commons-0.2.jar
2、 创建DBManager_c3p0
3、 测试代码
四、C3P0与DBCP的区别
1、dbcp没有自动的去回收空闲连接的功能
2、c3po有自动回收空闲连接功能
自己写了个数据库连接池的小例子,只实现了主要功能,之后再慢慢补充:
public class ConnectionPool implements Serializable{
/**
* 数据结构选择Map数据结构 Map<Connection,Boolean>
* Map集合中key用来存储连接对象,value部分用来存储关联的连接对象是否空闲,true表示空闲,false表示正在使用
*/
private static Map<Connection,Boolean> connsPool;
/**
* 连接池中最小连接数 minConn
*/
private static Long MINCONN;
/**
* 连接池中最大连接数 maxConn
*/
private static Long MAXCONN;
/**
* 最大等待时间 maxWait
*/
private static Long MAXWAIT ; //最大等待时间20s
/**
* 连接数据库的驱动类
*/
private static String DRIVERCLASS;
/**
* 用户名
*/
private static String USERNAME;
/**
* 密码
*/
private static String PASSWORD;
/**
* URL
*/
private static String URL ;
/**
* 核心方法:从连接池中获取连接对象
* @return 返回空闲的连接对象
*/
public static Connection getConnection(){
/**
* 遍历连接池,找空闲的连接对象
*/
Set<Connection> conns = connsPool.keySet();
for(Connection conn:conns){
Boolean isFree = connsPool.get(conn);
if(isFree){//空闲
//把空闲的Connection对象改成忙碌的。
connsPool.put(conn, false);
System.out.println("连接数:"+connsPool.size()+",空闲"+getFreeConnectionsCount());
return conn;
}
}
//如果程序能执行到此处证明连接池中没有空闲的连接
//如果没有空闲连接,而且连接数没有超过最大连接数,创建新的连接,将新的连接加入到连接池中
//获取连接数
Long connsCount = (long)conns.size();
if(connsCount<MAXCONN){//如果连接池中的连接数没有到最大连接数.创建新的连接
Connection conn = getConn();
connsPool.put(conn, false);
System.out.println("连接数:"+connsPool.size()+",空闲"+getFreeConnectionsCount());
return conn;
}
//如果没有空闲连接,并且连接数已经到极限,等待.等待最大时间是20s
for(int i=0;i<MAXWAIT/1000;i++){//每隔1s去连接池中获取空闲连接
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//寻找空闲连接
for(Connection conn:conns){
Boolean isFree = connsPool.get(conn);
if(isFree){
connsPool.put(conn, false);
System.out.println("连接数:"+connsPool.size()+",空闲"+getFreeConnectionsCount());
return conn;
}
}
}
return null;
}
/**
* 提供获取连接对象的方法
*/
public static Connection getConn(){
Connection conn = null;
try{
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
}catch(Exception e){
e.printStackTrace();
}
return conn;
}
//静态语句块负责初始化连接池
static{
/**
* 读取数据源
*/
Properties p = new Properties();
try {
p.load(new FileInputStream("src/DataSource.properties"));
MINCONN = Long.parseLong(p.getProperty("minConn"));
MAXCONN = Long.parseLong(p.getProperty("maxConn"));
MAXWAIT = Long.parseLong(p.getProperty("maxWait"));
DRIVERCLASS = p.getProperty("driverClass");
USERNAME = p.getProperty("username");
PASSWORD = p.getProperty("password");
URL = p.getProperty("url");
Class.forName(DRIVERCLASS);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("初始化连接池....");
connsPool = new HashMap<Connection,Boolean>();//创建数据结构对象
System.out.println("开始创建连接对象...");
for(int i=0;i<MINCONN;i++){
Connection conn = getConn();
connsPool.put(conn,true);
System.out.println("创建第"+(i+1)+"个连接对象完毕,并将该连接对象("+conn+")添加到连接池中....");
}
System.out.println("连接池初始化完毕....");
System.out.println("当前连接池中空闲连接数:"+getFreeConnectionsCount());
}
/**
* 获取当前连接池中空闲连接对象的个数
*/
public static Long getFreeConnectionsCount(){
Long freeConnectionsCount = 0L;
Set<Connection> conns = connsPool.keySet();
for(Connection conn:conns){
Boolean isFree = connsPool.get(conn);
if(isFree){//如果空闲
++freeConnectionsCount;
}
}
return freeConnectionsCount;
}
/**
* 用户释放连接对象
*/
public static void release(Connection conn){
Set<Connection> conns = connsPool.keySet();
for(Connection c:conns){
if(conn==c){
connsPool.put(c, true);
return;
}
}
}
//测试
/*public static void main(String[] args) throws Exception{
Connection conn1 = ConnectionPool.getConnection();
System.out.println(conn1);
Connection conn2 = ConnectionPool.getConnection();
System.out.println(conn2);
Connection conn3 = ConnectionPool.getConnection();
System.out.println(conn3);
Connection conn4 = ConnectionPool.getConnection();
System.out.println(conn4);
*//**
* 释放conn1,conn2
*//*
ConnectionPool.release(conn1);
ConnectionPool.release(conn2);
Connection conn5 = ConnectionPool.getConnection();
System.out.println(conn5);
Connection conn6 = ConnectionPool.getConnection();
System.out.println(conn6);
Connection conn7 = ConnectionPool.getConnection();
System.out.println(conn7==null?"没有获取到连接":"获取到连接");
}*/
}