连接池的概念
1)连接池是一个进程
多个连接是在一个进程里面存储、管理的。这个进程保存所有的连接,当我们打开连接,如果有未用连接可用,则返回该连接。如果池中的连接都用完了,则创建一个新的连接保存到连接池。而但我们关闭连接的时候,连接池里面并不关闭连接,而是返回连接池中并标记为可重用的状态,等待重新连接直到等待超时。再次打开连接的时候,我们就可以重用上次的连接。如果在这个时间内没有连接请求(打开连接),这个数据库连接将被关闭,并从连接池中移除这个连接实例。如果池中连接到达了最大连接数,请求进入等待队列直到空闲连接可用。如果在可获取连接对象之前超时期限已过(由 Connect Timeout 连接字符串属性来决定),则将出错。
2)该进程保存连接并使其处于活动状态,使连接可以被重复使用
应用程序访问底层的数据源的时候是通过OS的数据访问组件或者说Sql Client数据访问提供程序进行访问的。都是通过系统提供的组件去访问数据库服务器的数据库的。连接是通过这些组件建立的,连接池是在这些组件之上的,它存在于应用程序的进程里面。因此需要重用连接,就是在这一个进程里面重用。例如:两个WinForm程序在不同的计算机上,他们同时连接一个数据库服务器,这个时候,连接池就没办法起作用,因为连接池是一个进程里面。这时候,我们可以在数据库服务器上层搭建一个Web Service,而Web Service 和数据库服务器之间使用的是连接池,数据库服务器的压力就会小。
如果没有连接池
1)连接到数据源
– 建立物理通道(例如套接字或命名管道)
– 与服务器进行初次握手
– 分析连接字符串信息
– 由服务器对连接进行身份验证
– 运行检查以便在当前事务中登记(连接的环境是不是分布式事务)
另:不仅是连接池,还有使用的比较多的对象,我们也可以将之放在对象池,以便下次使用。
连接池的作用
1)通过数据库连接池,应用程序可以重用池中现有的连接中现有的连接,而不必反复与数据库建立新的连接。
2)使用连接池可显著提高应用程序的可伸缩,因为有限数量的数据库连接可以为数量大得多的客户端提供服务。例如:数据库应用里面,上万的用户可能只需要少量的连接,因为客户端不可能同时并发的大量的访问数据库。故少量的连接可以支持大量的服务,提高程序的可伸缩性。
3)同时,由于可以节省建立新连接所需的大由于可以节省建立新连接所需的大量时间,使用连接池还能够改善性能。
4)连接池对于应用程序来说是透明的,例如:conn.Open() 和 conn.Close()。
连接池的的初步代码
package pool; import java.io.FileInputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; import java.util.Vector; /** * 连接池 * @author * */ public class ConnectionPool { //私有属性driver名称 private String driverClassName; //私有属性url private String url; //私有属性username private String username; //私有属性password private String password; //私有属性线程安全集合对象Vector private Vector<Connection> pool; /** *连接池的大小,也就是连接池中有多少个数据库连接。 */ private int poolSize = 1; /** * 单例模式(懒汉模式) */ private static ConnectionPool instance = null; /** * 私有的构造方法,禁止从外部创建本类的对象,要想获得本类的对象,通过<code>getInstance()<code>方法。 * 使用了设计模式中的(单例模式) */ private ConnectionPool() { init(); } /** * 连接池初始化方法,读取属性文件的内容,建立连接池中的初始连接。 */ private void init() { pool = new Vector<Connection>(poolSize); readConfig(); addConnection(); } /** * 返回连接到连接池中 */ public synchronized void release(Connection conn) { pool.add(conn); } /** * 关闭连接池中的所有数据库连接 */ public synchronized void closePool() { for (int i = 0; i < pool.size(); i++) { try { pool.get(i).close(); } catch (SQLException e) { e.printStackTrace(); } pool.remove(i); } } /** * 返回当前连接池的一个对象 */ public static ConnectionPool getInstance() { //循环条件下,从连接池内拿走一个连接,连接池内就少一个连接 if (instance == null) { instance = new ConnectionPool(); } return instance; } /** * 返回连接池中的一个数据库连接 */ public synchronized Connection getConnection() { if (pool.size() > 0) { Connection conn = pool.get(0); pool.remove(conn); return conn; } else { return null; } } /** * 在连接池中创建初始设置的数据库连接 */ private void addConnection() { Connection conn = null; //循环创建poolsize个连接对象 for (int i = 0; i < poolSize; i++) { try { //加载类驱动 Class.forName(driverClassName); //驱动程序连接数据库 conn = DriverManager.getConnection(url, username, password); //将创建的连接对象放进池中 pool.add(conn); } catch (Exception e) { e.printStackTrace(); } } } /** * 读取设置连接池的属性文件 */ private void readConfig() { try { //读取路径并加载路径 String path = System.getProperty("user.dir") + "\\dbpool.properties"; FileInputStream is = new FileInputStream(path); Properties props = new Properties(); props.load(is); //将文件内的内容加载到属性中 this.driverClassName = props.getProperty("driverClassName"); this.username = props.getProperty("username"); this.password = props.getProperty("password"); this.url = props.getProperty("url"); this.poolSize = Integer.parseInt(props.getProperty("poolSize")); } catch (Exception e) { e.printStackTrace(); System.out.println("读取属性文件出错!"); } } }