DatabaseConnectionPool--数据库连接池

来源:互联网 发布:海外淘宝网 编辑:程序博客网 时间:2024/05/22 09:50

研究数据库连接池学习的开始,是从一篇关于数据库连接池的理论文章开始,地址如下:
    《基于JDBC的数据库连接池技术研究与应用》
    
http://hi.baidu.com/tryonmind/blog/item/261ad4549d7e3859d109060f.html 

    里面有相当多的java关键字及其方法尚不知晓,只能一边查文档,以便学习了。记录如下:

    1.Vector 
    声明方法:private Vector drivers = new Vector();

    说明:Vector 类可以实现可增长的对象“数组”。优点:Vector 的大小可以根据需要增大或缩小,以适应创建Vector 后进行添加或移除项的操作。此间涉及向量的操作。详细操作方法可以查阅 java5.0的API帮助文档。

    这里遭遇的一个可能性问题是:你是jdk1.4还是在jdk5.0环境下编译,对Vecter声明使用有差异,5.0比较严格。

    2.Hashtable 哈希表
    声明方法:Hashtable ht = new
 Hashtable();

    说明:哈希表是一种重要的存储方式,也是一种常见的检索方法。其基本思想是将关系码的值作为自变量,通过一定的函数关系计算出对应的函数值,把这个数值解释为结点的存储地址,将结点存入计算得到存储地址所对应的存储单元。检索时采用检索关键码的方法。

    现在哈希表有一套完整的算法来进行插入、删除和解决冲突。
    在Java中哈希表用于“存储对象”,实现快速检索。
    Hashtable 的实例有两个参数影响其性能:初始容量 和加载因子容量 是哈希表中 的数量,初始容量 就是哈希表创建时的容量。

    java的支持:java.util.Hashtable<K,V> 哈希表的操作也是很丰富。


          
    3.Properties 属性列表

    声明方法:Properties dbProps = new Properties();
    public class Properties extends Hashtable<Object,Object>

    说明:Properties 继承于 Hashtable,所以可对 Properties 对象应用 put 和 putAll 方法,但强烈建议使用应该使用 setProperty 方法        

    Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。 

    例如连接池中读取属性文件的应用:

InputStream is = getClass().getResourceAsStream("db.properties");//
  Properties dbProps = new Properties();
  try

  {
   dbProps.load( is );
  }

  catch ( Exception e )
  
{
   System.err.println( "不能读取属性文件" + "请确保db.properties在CLASSPATH指定的路径中"
 ); 
   return
;
  }

   
    主要方法有:
     String getProperty(String key) 用指定的键在此属性列表中搜索属性。    
     getProperty(String key, String defaultValue)用指定的键在属性列表中搜索属性。 
     
     
      void list(PrintStream out) 将属性列表输出到指定的输出流。         
     list(PrintWriter out) 将属性列表输出到指定的输出流。
           
      void load(InputStream inStream) 从输入流中读取属性列表(键和元素对)。        
      void loadFromXML(InputStream in) 将指定输入流中由 XML 文档所表示的所有属性加载到此属性表中。
  
    Enumeration<?> propertyNames() 返回属性列表中所有键的枚举,如果在主属性列表中未找到同名的键,则包括默认属性列表中不同的键。

    更详细的就不提,查文档 

    连接池应用:
     String driverClasses = props.getProperty("drivers");读取到属性文件中drivers的值


    4.Enumeration

    说明:实现 Enumeration 接口的对象,它生成一系列元素,一次生成一个。连续调用 nextElement 方法将返回一系列的连续元素。

    boolean hasMoreElements()  测试此枚举是否包含更多的元素。 
    E nextElement()   如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
     
    这些方法主要通过向量的元素、哈希表的键以及哈希表中的值进行枚举。枚举也用于将输入流指定到 SequenceInputStream 中。

    连接池应用:
     Enumeration propsNames = props.propertyNames(); //读取属性列表的值,用Enumeration进行标记和调用





一、从Java类来分析连接池的构架,可以了解以下几点:

 1. 连接池实际上分2个部分:连接池类和连接池管理类。
 
 2. 连接池类作用是:创建和毁灭连接池、创建连接和关闭连接、遍历查询并提供有效连接、处理无效连接。
 
 3. 连接池管理类的作用是:初始化操作(提供创建一个连接池的操作方法、获取数据库的用户密码驱动信息提供给连接池类使用)、从连接池获取有效连接提供给用户、追踪连接操作和记录日志。
 
 4. 可以通过连接池管理类创建一个或者多个连接池。连接池管理类是连接池类的外覆类(wrapper),符合单例模式,即系统中只能有一个连接池管理类的实例。
 
 5. 并发问题:为了使连接管理服务具有最大的通用性,必须考虑多线程环境,即并发问题。Java语言自身提供了对并发管理的支持,使用synchronized关键字即可确保线程是同步的。使用方法为直接在类方法前面加上synchronized关键字,如:public synchronized Connection getConnection()


 二、分析连接池管理类:

 1. 首先是初始化方法:调用以下方法,实现读取属性文件、注册驱动、连接池创建。

        private void init()
        
{
            dbProps.load(getClass().getResourceAsStream("db.properties"));    //读取属性文件

            loadDrivers(dbProps);    //加载和注册所有JDBC驱动程序
            createPools(dbProps);    //根据指定属性创建连接池实例,props为连接池属性        
        }

 2. 获取数据库用户密码进行创建连接池操作。

        private void createPools (Properties props)
        
{
            DBConnectionPool pool = new
 DBConnectionPool (poolName,url,user,password,max);
            pools.put (poolName,pool) ;
        
            log ("成功创建连接池" +
 poolName) ;
        }

 3. 注册驱动

        private void loadDrivers ( Properties props )
        
{    
            String driverClasses = props.getProperty("drivers"
);
            Driver driver =
 (Driver)Class.forName(driverClasses).newInstance();            
            DriverManager.registerDriver(driver);
            
            drivers.addElement(driver);
            log("成功注册JDBC驱动程序" +
 driverClasses );
        }

 4. 获取空闲连接

        public Connection getConnection (String name)
        
{
            DBConnectionPool pool =
 (DBConnectionPool) pools.get(name);
            if ( pool != null
 )    
            
{
                return
 pool.getConnection();
            }
    
            else

            {
                return null
 ;
            }
        
        }

 5. 关闭连接,撤销所有驱动的注册

        public synchronized void release()
        
{
            Enumeration allpools =
 pools.elements(); 
            while
 (allpools.hasMoreElements()) 
            
{
                DBConnectionPool pool =
 (DBConnectionPool) allpools.nextElement();
                pool.release();
            }
    
        }

 三、分析连接池类:

 1. 获取管理类传递的数据库库参数值

        public DBConnectionPool ( String name, String URL, String user,String password,int maxConn )
        
{
            this.name =
 name ;
            this.URL =
 URL ;
            this.user =
 user ;
            this.password =
 password ;
            this.maxConn =
 maxConn ;
        }

        

 2. 释放有效连接 

        public synchronized Connection getConnection()
        
{
            //
从连接池获得一个可用连接,如果没有空闲且连接数在最大连接范围内,则创建新连接
            
//
如果原来登记的连接无效,则从向量中删除
            
//然后递归调用自己以尝试新的可用连接        

            con = (Connection) freeConnections.firstElement() ;
            freeConnections.removeElementAt(0
);    
            try

            {
                if
 ( con.isClosed() )
                
{
                    log("从连接池" + name + "删除一个无效连接"
);                            
                    con = getConnection();//递归调用自己,尝试获得可用连接

                }
    
            }

            catch (SQLException e )
            
{
                    log("从连接池" + name + "删除一个无效连接"
);                            
                    con = getConnection();    //递归调用自己,尝试获得可用连接                

            }
                
        }

3. 关闭所有连接

        public synchronized void release()
        
{
            Enumeration allConnections =
 freeConnections.elements(); 
            while
 (allConnections.hasMoreElements()) 
            
{
                Connection con =
 (Connection) allConnections.nextElement();
                try

                {
                    con.close() ;
                    log ("关闭连接池" + name + "中的一个连接"
) ;    
                }

                catch (SQLException e )
                
{
                    log ("无法关闭连接池" + name + "中的一个连接"
) ;    
                }

            }

            freeConnections.removeAllElements();    
        }

 4. 创建新连接

        private Connection newConnection()
        
{
            if ( user == null
 )
            
{
                con =
 DriverManager.getConnection(URL);    
            }

            else
            {
                con =
 DriverManager.getConnection( URL,user,password );    
            }

            log( "连接池" + name + "创建一个新的连接" ) ;            
        }

 这是连接池的简单的基本构架,实用性很一般,扩展性和操作性比较差,仅供学习理解所用,需要进行更好的完善


     连接池建立起来后的应用就相对简单多了,不过事情往往不是都很顺利的,一套完整的应用是需要所有细节的链子完整的连接起来,这中间需要进行一些琐碎的工作。

       我使用的数据库是 ms sql server,配置需要花费一些手脚。

        1.下载sql server的驱动,有3个文件:msbase.jar、mssqlserver.jar、msutil.jar。具体只要上网一搜,就知道哪里下载了。下载完毕后将这个文件放到tomcat的/common/lib里面,或者是放在网站文件夹的web-inf/lib里面。如果你以后是使用别人的空间,那就最好放在自己的网站文件夹中。

        2.将连接池Java编译文件的DBConnectionManager.class文件放在web-inf/classes/database/目录下,同时需要记得修改连接数据库的属性文件db.properties,前缀都是连接池的名字。

        3.下面是一个连接池的应用测试页面。


<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.sql.*,
                 java.util.*,
                 database.DBConnectionManager,
                 metro.common.*" 

%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<title>MS SQL Server 连接测试</title>
</head>

<body>
<%
    DBConnectionManager connMgr ;
    ResultSet rs 
null ;
    Statement stmt = null
 ;

        connMgr =
 DBConnectionManager.getInstance();
        Connection con = connMgr .getConnection("sqlpool"
);
        if ( con == null
 )
        
{
            out.print("不能获取数据库连接"
);
            return
 ;
        }

        
        String sql 
= " select * from products " ;
        stmt =
 con.createStatement();        
        rs =
 stmt.executeQuery(sql);
        out.print("产品数据:"
) ;
        while
 ( rs.next() )
        
{
            out.print("<table>"
) ;
            out.print("<tr>"
) ;
            out.print("<td>"+ rs.getInt(1) +"</d>"
) ;        
            out.print("<td>"+ rs.getString(2) +"</d>"
) ;                    
            out.print("</tr>"
) ;            
            out.print("</table>"
) ;
        }



%>


</body>
</html>

        4.这里需要认识一个方法,就是凡是.class文件都是放在classes文件夹下,凡是jar、servlet文件都是放在lib文件夹下,莫搞混了


        5.这里顺便学习java的一个很重要的关键字synchronized

        (一)、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

        (二)、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

        (三)、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。



0 0
原创粉丝点击