数据库连接池的好处.txt-//自私,让我们只看见自己却容不下别人。
如果发短信给你喜欢的人,他不回,不要再发。
看着你的相片,我就特冲动的想P成黑白挂墙上!有时,不是世界太虚伪,只是,我们太天真。
数据库连接池的好处对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。
这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。
但是对于一个复杂的数据库应用,情况就完全不同了。
频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。
连接复用。
通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。
对于共享资源,有一个很著名的设计模式:资源池。
该模式正是为了解决资源频繁分配、释放所造成的问题的。
把该模式应用到数据库连接管理领域,就是建立一个数据库连接池,提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用。
数据库连接池的基本原理是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取和返回方法。
如:外部使用者可通过getConnection 方法获取连接,使用完毕后再通过releaseConnection 方法将连接返回,注意此时连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。
数据库连接池技术带来的优势:1.资源重用由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。
在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
2.更快的系统响应速度数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。
此时连接的初始化工作均已完成。
对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
3.新的资源分配手段对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术。
某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。
4.统一的连接管理,避免数据库连接泄漏在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。
从而避免了常规数据库连接操作中可能出现的资源泄漏。
一个最小化的数据库连接池实现:public class DBConnectionPool implements ConnectionPool{private static Vector pool;private final int POOL_MAX_SIZE = 20;/** 获取数据库连接* 如果当前池中有可用连接,则将池中最后一个返回,如果没有,则新建一个返回*/public synchronized Connection getConnection() throws DBException {if (pool == null){pool = new Vector();}Connection conn;if (pool.isEmpty()){conn = createConnection();} else {int last_idx = pool.size() - 1;conn = (Connection) pool.get(last_idx);pool.remove(pool.get(last_idx));}return conn;}/** 将使用完毕的数据库连接放回备用池。
* 判断当前池中连接数是否已经超过阀值(POOL_MAX_SIZE),* 如果超过,则关闭该连接。
* 否则放回池中以备下次重用。
*/public synchronized void releaseConnection(Connection conn){if (pool.size() > POOL_MAX_SIZE){try{conn.close();} catch (SQLException e){e.printStackTrace();}}else{pool.add(conn);}}/*** 读取数据库配置信息,并从数据库连接池中获得数据库连接* @return* @throws DBException*/private static Connection createConnection() throws DBException{Connection conn;try{Class.forName("oracle.jdbc.driver.OracleDriver");conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:oracle", "personal", "personal");return conn;} catch (ClassNotFoundException e){throw new DBException("ClassNotFoundException when loading JDBC Driver");}catch (SQLException e){throw new DBException("SQLException when loading JDBC Driver");}}}上面的代码实现了一个最简单的连接池,因为简单,所以明了,目的只是展示数据库连接池实现的一般原理。
完备的连接池实现固然错综复杂,但就其根本而言,还是源自同样的思想。
先脱离连接池本身的具体实现,我们看看这段代码在实际应用中可能产生的问题,注意到,由于getConnection 方法返回的是一个标准的JDBC Connection,程序员由于编程习惯,可能会习惯性的调用其close 方法关闭连接。
如此一来,连接无法得到重用,数据库连接池机制形同虚设。
为了解决这个问题,比较好的途径有:1. Decorator 模式2. Dynamic Proxy 模式下面我们就这两种模式进行一些探讨Decorator模式“Decorator 模式的主要目的是利用一个对象,透明的为另一个对象添加新的功能”。
这句话是从GOF 关于设计模式的经典著作《设计模式-可复用面向对象软件的基础》一书中关于Decorator 模式的描述直译而来,可能比较难以理解。
简单来讲,就是通过一个Decorator 对原有对象进行封装,同时实现与原有对象相同的接口,从而得到一个基于原有对象的,对既有接口的增强性实现。
其UML 描述如下:对于前面所讨论的Connection 释放的问题,理所当然,我们首先想到的是,如果能让JDBC Connection 在执行close 操作时自动将自己返回到数据库连接池中,那么所有问题都将迎刃而解,但是,JDBC Connection 自己显然无法根据实际情况判断何去何从。
此时,引入Decorator 模式来解决我们所面对的问题就非常合适。
首先,我们引入一个ConnectionDecorator 类:public class ConnectionDecorator implements Connection{Connection dbconn;public ConnectionDecorator(Connection conn){this.dbconn = conn; //实际从数据库获得的Connection引用}/* 此方法将被子类覆盖,以实现数据库连接池的连接返回操作* @see java.sql.Connection#close()*/public void close() throws SQLException{this.dbconn.close();}/* (non-Javadoc)* @see java.sql.Connection#commit()*/public void commit() throws SQLException{mit();//调用实际连接的commit方法}……//以下各个方法类似,均调用dbconn.xxx方法作为Connection接口定义的功能。
……}可以看到,ConnectionDecorator 类实际上是对传入的数据库连接加上了一个外壳,它实现了java.sql.Connection接口,不过本身并没有实现任何实际内容,只是简单的把方法的实现委托给运行期实际获得的Connection 实例,而从外部来看,ConnectionDecorator与普通的Connection 实例并没有什么区别,因为它们实现了同样的接口,对外提供了同样的功能调用。
目标很清楚,通过这样的封装,我们的ConnectionDecorator 对于外部的程序员而言,调用方法与普通的JDBC Connection 完全相同,而在内部通过对ConnectionDecorator 的修改,我们就可以透明的改变现有实现,为之增加新的特性:public class PooledConnectionextends ConnectionDecoratorimplements Connection /????还需要实现这个接口吗?{private ConnectionPool connPool;public PooledConnection(ConnectionPool pool, Connection conn){super(conn);connPool = pool;}/*** 覆盖close方法,将数据库连接返回连接池,而不是直接关闭连接*/public void close() throws SQLException{connPool.releaseConnection(this.dbconn);}……}为了应用新的PooledConnection,我们需要对原本的DBConnectionPool.getConnection 和releaseConnection 方法稍做改造:public synchronized Connection getConnection() throws DBException{if (pool == null){pool = new Vector();}Connection conn;if (pool.isEmpty()){conn = createConnection();}else{int last_idx = pool.size() - 1;conn = (Connection) pool.get(last_idx);pool.remove(pool.get(last_idx));}return new PooledConnection(this,conn);}public synchronized void releaseConnection(Connection conn){if (conn instanceof PooledConnection || pool.size() > POOL_MAX_SIZE){try{conn.close();}catch (SQLException e){e.printStackTrace();}}else{pool.add(conn);}}此时,获取数据库连接后,调用者只需要按照JDBC Connection 的标准用法进行调用即可,从而实现了数据库连接池的透明化。