1、实现jdbc数据库连接池实现jdbc数据库连接池收藏网上看到一位大牛写的连接类。此类非常简单,免去了网上众多资料里所说的麻烦的tomcat配置,更强的是它可以通用!不仅oracle,mysql,sqlserver2000都行,因为它依据的是你自己连接数据库的驱动。当然首先你要保证你拥有一个能连接自己数据库的对应驱动类。如下面以mysql为例:先附上牛人(可惜没留名!)的原码:来自“豆豆在线”packagemyDB;importjava.io.*;importjava.sql.*;importjava.util.*;importjava.util.Date;/*管理类DBConnectionMa
2、nager支持对一个或多个由属性文件定义的数据库连接*池的访问.客户程序可以调用getInstance()方法访问本类的唯一实例.*/publicclassDBConnectionManagerstaticprivateDBConnectionManagerinstance;/唯一实例staticprivateintclients;privateVectordrivers=newVector();privatePrintWriterlog;privateHashtablepools=newHashtable();/*返回唯一实例.如果是第一次调用此方法,则创建实例*returnDBConnec
3、tionManager唯一实例*/staticsynchronizedpublicDBConnectionManagergetInstance()if(instance=null)instance=newDBConnectionManager();clients+;returninstance;/*建构函数私有以防止其它对象创建本类实例*/privateDBConnectionManager()init();/*将连接对象返回给由名字指定的连接池*paramname在属性文件中定义的连接池名字*paramcon连接对象*/publicvoidfreeConnection(Stringname,
4、Connectioncon)DBConnectionPoolpool=(DBConnectionPool)pools.get(name);if(pool!=null)pool.freeConnection(con);/*获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数*限制,则创建并返回新连接*paramname在属性文件中定义的连接池名字*returnConnection可用连接或null*/publicConnectiongetConnection(Stringname)DBConnectionPoolpool=(DBConnectionPool)pools.ge
5、t(name);if(pool!=null)returnpool.getConnection();returnnull;/*获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制,*则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接.*paramname连接池名字*paramtime以毫秒计的等待时间*returnConnection可用连接或null*/publicConnectiongetConnection(Stringname,longtime)DBConnectionPoolpool=(DBConnectionPool)pools.get(name);if(poo
6、l!=null)returnpool.getConnection(time);returnnull;publicintgetClient()returnclients;/*关闭所有连接,撤销驱动程序的注册*/publicsynchronizedvoidrelease()/等待直到最后一个客户程序调用if(-clients!=0)return;EnumerationallPools=pools.elements();while(allPools.hasMoreElements()DBConnectionPoolpool=(DBConnectionPool)allPools.nextElement
7、();pool.release();EnumerationallDrivers=drivers.elements();while(allDrivers.hasMoreElements()Driverdriver=(Driver)allDrivers.nextElement();tryDriverManager.deregisterDriver(driver);log(撤销JDBC驱动程序+driver.getClass().getName()+的注册);catch(SQLExceptione)log(e,无法撤销下列JDBC驱动程序的注册:+driver.getClass().getName(
8、);/*根据指定属性创建连接池实例.*paramprops连接池属性*/privatevoidcreatePools(Propertiesprops)EnumerationpropNames=props.propertyNames();while(propNames.hasMoreElements()Stringname=(String)propNames.nextElement();if(name.endsWith(.url)StringpoolName=name.substring(0,name.lastIndexOf(.);Stringurl=props.getProperty(pool
9、Name+.url);if(url=null)log(没有为连接池+poolName+指定URL);continue;Stringuser=props.getProperty(poolName+.user);Stringpassword=props.getProperty(poolName+.password);Stringmaxconn=props.getProperty(poolName+.maxconn,0);intmax;trymax=Integer.valueOf(maxconn).intValue();catch(NumberFormatExceptione)log(错误的最大连接
10、数限制:+maxconn+.连接池:+poolName);max=0;DBConnectionPoolpool=newDBConnectionPool(poolName,url,user,password,max);pools.put(poolName,pool);log(成功创建连接池+poolName);/*读取属性完成初始化*/privatevoidinit()InputStreamis=getClass().getResourceAsStream(/db.properties);PropertiesdbProps=newProperties();trydbProps.load(is);
11、System.out.print(读取数据成功!);catch(Exceptione)System.err.println(不能读取属性文件.+请确保db.properties在CLASSPATH指定的路径中);return;StringlogFile=dbProps.getProperty(logfile,DBConnectionManager.log);System.out.print(logFile);trylog=newPrintWriter(newFileWriter(logFile,true),true);catch(IOExceptione)System.err.println(
12、无法打开日志文件:+logFile);log=newPrintWriter(System.err);loadDrivers(dbProps);createPools(dbProps);/*装载和注册所有JDBC驱动程序*paramprops属性*/privatevoidloadDrivers(Propertiesprops)StringdriverClasses=props.getProperty(drivers);StringTokenizerst=newStringTokenizer(driverClasses);while(st.hasMoreElements()Stringdriver
13、ClassName=st.nextToken().trim();tryDriverdriver=(Driver)Class.forName(driverClassName).newInstance();DriverManager.registerDriver(driver);drivers.addElement(driver);log(成功注册JDBC驱动程序+driverClassName);catch(Exceptione)log(无法注册JDBC驱动程序:+driverClassName+,错误:+e);/*将文本信息写入日志文件*/privatevoidlog(Stringmsg)lo
14、g.println(newDate()+:+msg);/*将文本信息与异常写入日志文件*/privatevoidlog(Throwablee,Stringmsg)log.println(newDate()+:+msg);e.printStackTrace(log);/*此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最*大连接数为止.在返回连接给客户程序之前,它能够验证连接的有效性.*/classDBConnectionPoolprivateintcheckedOut;privateVectorfreeConnections=newVector();privateintmaxCo
15、nn;privateStringname;privateStringpassword;privateStringURL;privateStringuser;/*创建新的连接池*paramname连接池名字*paramURL数据库的JDBCURL*paramuser数据库帐号,或null*parampassword密码,或null*parammaxConn此连接池允许建立的最大连接数*/publicDBConnectionPool(Stringname,StringURL,Stringuser,Stringpassword,intmaxConn)this.name=name;this.URL=U
16、RL;this.user=user;this.password=password;this.maxConn=maxConn;/*将不再使用的连接返回给连接池*paramcon客户程序释放的连接*/publicsynchronizedvoidfreeConnection(Connectioncon)/将指定连接加入到向量末尾freeConnections.addElement(con);checkedOut-;notifyAll();/*从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接*数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之,*然后递归调用自己以尝
17、试新的可用连接.*/publicsynchronizedConnectiongetConnection()Connectioncon=null;if(freeConnections.size()0)/获取向量中第一个可用连接con=(Connection)freeConnections.firstElement();freeConnections.removeElementAt(0);tryif(con.isClosed()log(从连接池+name+删除一个无效连接);/递归调用自己,尝试再次获取可用连接con=getConnection();catch(SQLExceptione)log(
18、从连接池+name+删除一个无效连接);/递归调用自己,尝试再次获取可用连接con=getConnection();elseif(maxConn=0|checkedOut=timeout)/wait()返回的原因是超时returnnull;returncon;/*关闭所有连接*/publicsynchronizedvoidrelease()EnumerationallConnections=freeConnections.elements();while(allConnections.hasMoreElements()Connectioncon=(Connection)allConnectio
19、ns.nextElement();trycon.close();log(关闭连接池+name+中的一个连接);catch(SQLExceptione)log(e,无法关闭连接池+name+中的连接);freeConnections.removeAllElements();/*创建新的连接*/privateConnectionnewConnection()Connectioncon=null;tryif(user=null)con=DriverManager.getConnection(URL);elsecon=DriverManager.getConnection(URL,user,passw
20、ord);log(连接池+name+创建一个新的连接);catch(SQLExceptione)log(e,无法创建下列URL的连接:+URL);returnnull;returncon;对应的讲解:该类在209至345行实现,它表示指向某个数据库的连接池。数据库由JDBCURL标识。一个JDBCURL由三部分组成:协议标识(总是jdbc),驱动程序标识(如odbc、idb、oracle等),数据库标识(其格式依赖于驱动程序)。例如,jdbc:odbc:demo,即是一个指向demo数据库的JDBCURL,而且访问该数据库要使用JDBC-ODBC驱动程序。每个连接池都有一个供客户程序使用的名字
21、以及可选的用户帐号、密码、最大连接数限制。如果Web应用程序所支持的某些数据库操作可以被所有用户执行,而其它一些操作应由特别许可的用户执行,则可以为两类操作分别定义连接池,两个连接池使用相同的JDBCURL,但使用不同的帐号和密码。类DBConnectionPool的建构函数需要上述所有数据作为其参数。如222至238行所示,这些数据被保存为它的实例变量:如252至283行、285至305行所示,客户程序可以使用DBConnectionPool类提供的两个方法获取可用连接。两者的共同之处在于:如连接池中存在可用连接,则直接返回,否则创建新的连接并返回。如果没有可用连接且已有连接总数等于最大限制
22、数,第一个方法将直接返回null,而第二个方法将等待直到有可用连接为止。所有的可用连接对象均登记在名为freeConnections的向量(Vector)中。如果向量中有多于一个的连接,getConnection()总是选取第一个。同时,由于新的可用连接总是从尾部加入向量,从而使得数据库连接由于长时间闲置而被关闭的风险减低到最小程度。第一个getConnection()在返回可用连接给客户程序之前,调用了isClosed()方法验证连接仍旧有效。如果该连接被关闭或触发异常,getConnection()递归地调用自己以尝试获取另外的可用连接。如果在向量freeConnections中不存在任何
23、可用连接,getConnection()方法检查是否已经指定最大连接数限制。如已经指定,则检查当前连接数是否已经到达极限。此处maxConn为0表示没有限制。如果没有指定最大连接数限制或当前连接数小于该值,该方法尝试创建新的连接。如创建成功,则增加已使用连接的计数并返回,否则返回空值。如325至345行所示,创建新连接由newConnection()方法实现。创建过程与是否已经指定数据库帐号、密码有关。JDBC的DriverManager类提供多个getConnection()方法,这些方法要用到JDBCURL与其它一些参数,如用户帐号和密码等。DriverManager将使用指定的JDBCU
24、RL确定适合于目标数据库的驱动程序及建立连接。在285至305行实现的第二个getConnection()方法需要一个以毫秒为单位的时间参数,该参数表示客户程序能够等待的最长时间。建立连接的具体操作仍旧由第一个getConnection()方法实现。该方法执行时先将startTime初始化为当前时间。在while循环中尝试获得一个连接。如果失败,则以给定的时间值为参数调用wait()。wait()的返回可能是由于其它线程调用notify()或notifyAll(),也可能是由于预定时间已到。为找出wait()返回的真正原因,程序用当前时间减开始时间(startTime),如差值大于预定时间则返
25、回空值,否则再次调用getConnection()。把空闲的连接登记到连接池由240至250行的freeConnection()方法实现,它的参数为返回给连接池的连接对象。该对象被加入到freeConnections向量的末尾,然后减少已使用连接计数。调用notifyAll()是为了通知其它正在等待可用连接的线程。许多Servlet引擎为实现安全关闭提供多种方法。数据库连接池需要知道该事件以保证所有连接能够正常关闭。DBConnectionManager类负协调整个关闭过程,但关闭连接池中所有连接的任务则由DBConnectionPool类负责。在307至323行实现的release()方法供
26、DBConnectionManager调用。该方法遍历freeConnections向量并关闭所有连接,然后从向量中删除这些连接。四、类DBConnectionManager说明该类只能创建一个实例,其它对象能够调用其静态方法(也称为类方法)获得该唯一实例的引用。如031至036行所示,DBConnectionManager类的建构函数是私有的,这是为了避免其它对象创建该类的实例。DBConnectionManager类的客户程序可以调用getInstance()方法获得对该类唯一实例的引用。如018至029行所示,类的唯一实例在getInstance()方法第一次被调用期间创建,此后其引用就一直保存在静态变量instance中。每次调用getInstance()都增加一个DBConnectionManager的客户程序计数。即,该计数代表引用DBConnectionManager唯一实例的客户程序总数,它将被用于控制连接池的关闭操作。该类实例的初始化工作由146至168行之间的私有方法init()完成。其中getResourceAsStream()方法用于定位并打开外部文件。外部文件的定位方法依赖于类装载器的实现。标准的本地类装载器查找操作总是
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1