|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
最后我再次声明,我并没有说不看好java,实际上我对java很乐观的,毕竟她正在不断改进中,我相信她总有一天会和.net并驾齐驱的servlet|初级 保持数据库
JDBC利用数据库URL来讲明数据库驱动程序。数据库URL相似于通用的URL,但SUN在界说时作了一点简化,其语法以下:
Jdbc::[node]/[database]
个中子协定(subprotocal)界说驱动程序范例,node供应收集数据库的地位和端标语,前面跟可选的参数。比方:
Stringurl=”jdbc:inetdae:myserver:1433?language=us-english&sql7=true”
暗示接纳inetdae驱动程序毗连1433端口上的myserver数据库服务器,选择言语为美国英语,数据库的版本是mssqlserver7.0。
java使用经由过程指定DriverManager装进一个驱动程序类。语法以下:
Class.forName(“”);
或
Class.forName(“”).newInstance();
然后,DriverManager创立一个特定的毗连:
Connectionconnection=DriverManager.getConnection(url,login,password);
Connection接口经由过程指定命据库地位,登录名和暗码毗连数据库。Connection接口创立一个Statement实例实行必要的查询:
Statementstmt=connection.createStatement();
Statement具有各类办法(API),如executeQuery,execute等能够前往查询的了局集。了局集是一个ResultSet对象。详细的能够经由过程jdbc开辟文档检察。能够sun的站点高低载
上面例子来讲明:
importjava.sql.*;//输出JDBCpackage
Stringurl="jdbc:inetdae:myserver:1433";//主机名和端口
Stringlogin="user";//登录名
Stringpassword="";//暗码
try{
DriverManager.setLogStream(System.out);file://为显现一些的信息翻开一个流
file://挪用驱动程序,其名字为com.inet.tds.TdsDriver
file://Class.forName("com.inet.tds.TdsDriver");
file://设置超时
DriverManager.setLoginTimeout(10);
file://翻开一个毗连
Connectionconnection=DriverManager.getConnection(url,login,password);
file://失掉数据库驱动程序版本
DatabaseMetaDataconMD=connection.getMetaData();
System.out.println("DriverName: "+conMD.getDriverName());
System.out.println("DriverVersion: "+conMD.getDriverVersion());
file://选择数据库
connection.setCatalog("MyDatabase");
file://创立Statement
Statementst=connection.createStatement();
file://实行查询
ResultSetrs=st.executeQuery("SELECT*FROMmytable");
file://获得了局,输入到屏幕
while(rs.next()){
for(intj=1;j<=rs.getMetaData().getColumnCount();j++){
System.out.print(rs.getObject(j)+" ");
}
System.out.println();
}
file://封闭对象
st.close();
connection.close();
}catch(Exceptione){
e.printStackTrace();
}
创建保持池
一个静态的网站频仍地从数据库中获得数据来组成html页面。每次哀求一个页面城市产生数据库操纵。但毗连数据库倒是一个必要损耗大批工夫的事情,由于哀求毗连必要创建通信,分派资本,举行权限认证。这些事情很少能在一两秒内完成。以是,创建一个毗连,然后再后续的查询中都利用此毗连会年夜年夜地进步功能。由于servlet能够在分歧的哀求间坚持形态,因而接纳数据库毗连池是一个间接的办理计划。
Servlet在服务器的历程空间中驻留,能够便利而耐久地保护数据库毗连。接上去,我们先容一个完全的毗连池的完成。在完成中,有一个毗连池办理器办理毗连池对象,个中每个毗连池坚持一组数据库毗连对象,这些对象可为任何servlet所利用。
1、数据库毗连池类DBConnectionPool,供应以下的办法:
1、从池中获得一个翻开的毗连;
2、将一个毗连前往池中;
3、在封闭时开释一切的资本,并封闭一切的毗连。
别的,DBConnectionPool还处置毗连失利,好比超时,通信失利等毛病,而且依据预界说的参数限定池中的毗连数。
2、办理者类,DBConnetionManager,是一个容器将毗连池封装在内,并办理一切的毗连池。它的办法有:
1、挪用和注册一切的jdbc驱动程序;
2、依据参数表创立DBConnectionPool对象;
3、映照毗连池的名字和DBConnectionPool实例;
4、当一切的毗连客户加入后,封闭全体毗连池。
这些类的完成,和怎样在servlet中利用毗连池的使用在随后的文章中解说
DBConnectionPool类代表一个由url标识的数据库毗连池。后面,我们已提到,jdbc的url由三个部分构成:协定标识(老是jdbc),子协定标识(比方,odbc.oracle),和数据库标识(跟特定的数据库有关)。毗连池也具有一个名字,供客户程序援用。别的,毗连池另有一个用户名,一个暗码和一个最年夜同意毗连数。假如web使用同意一切的用户利用某些数据库操纵,而另外一些操纵是无限制的,则能够创立两个毗连池,具有一样的url,分歧的username和password,分离处置两类分歧的操纵权限。现把DBConnectionPool具体先容以下:
3、DBConnectionPool的机关
机关函数获得上述的一切参数:
publicDBConnectionPool(Stringname,StringURL,Stringuser,
Stringpassword,intmaxConn){
this.name=name;
this.URL=URL;
this.user=user;
this.password=password;
this.maxConn=maxConn;
}
将一切的参数保留在实例变量中。
4、从池中翻开一个毗连
DBConnectionPool供应两种办法来反省毗连。两种办法都前往一个可用的毗连,假如没有过剩的毗连,则创立一个新的毗连。假如最年夜毗连数已到达,第一个办法前往null,第二个办法则守候一个毗连被其他历程开释。
publicsynchronizedConnectiongetConnection(){
Connectioncon=null;
if(freeConnections.size()>0){
//PickthefirstConnectionintheVector
//togetround-robinusage
con=(Connection)freeConnections.firstElement();
freeConnections.removeElementAt(0);
try{
if(con.isClosed()){
log("Removedbadconnectionfrom"+name);
//Tryagainrecursively
con=getConnection();
}
}
catch(SQLExceptione){
log("Removedbadconnectionfrom"+name);
//Tryagainrecursively
con=getConnection();
}
}
elseif(maxConn==0||checkedOut<maxConn){
con=newConnection();
}
if(con!=null){
checkedOut++;
}
returncon;
}
一切余暇的毗连对象保留在一个叫freeConnections的Vector中。假如存在最少一个余暇的毗连,getConnection()前往个中第一个毗连。上面,将会看到,历程开释的毗连前往到freeConnections的开端。如许,最年夜限制地制止了数据库因一个毗连不举动而不测将其封闭的风险。
再前往客户之前,isClosed()反省毗连是不是无效。假如毗连被封闭了,大概一个毛病产生,该办法递回挪用获得另外一个毗连。
假如没有可用的毗连,该办法反省是不是最年夜毗连数被设置为0暗示无穷毗连数,大概到达了最年夜毗连数。假如能够创立新的毗连,则创立一个新的毗连。不然,前往null。
办法newConnection()用来创立一个新的毗连。这是一个公有办法,基于用户名和暗码来断定是不是能够创立新的毗连。
privateConnectionnewConnection(){
Connectioncon=null;
try{
if(user==null){
con=DriverManager.getConnection(URL);
}
else{
con=DriverManager.getConnection(URL,user,password);
}
log("Createdanewconnectioninpool"+name);
}
catch(SQLExceptione){
log(e,"Cannotcreateanewconnectionfor"+URL);
returnnull;
}
returncon;
}
jdbc的DriverManager供应一系列的getConnection()办法,可使用url和用户名,暗码等参数创立一个毗连。
第二个getConnection()办法带有一个超时参数timeout,当该参数指定的毫秒数暗示客户乐意为一个毗连守候的工夫。这个办法挪用前一个办法。
publicsynchronizedConnectiongetConnection(longtimeout){
longstartTime=newDate().getTime();
Connectioncon;
while((con=getConnection())==null){
try{
wait(timeout);
}
catch(InterruptedExceptione){}
if((newDate().getTime()-startTime)>=timeout){
//Timeouthasexpired
returnnull;
}
}
returncon;
}
部分变量startTime初始化以后的工夫。一个while轮回起首实验取得一个毗连,假如失利,wait()函数被挪用来守候必要的工夫。前面会看到,Wait()函数会在另外一个历程挪用notify()大概notifyAll()时前往,大概比及工夫流逝终了。为了断定wait()是由于何种缘故原由前往,我们用入手下手工夫减往以后工夫,反省是不是年夜于timeout。假如了局年夜于timeout,前往null,不然,在此挪用getConnection()函数。
5、将一个毗连前往池中
DBConnectionPool类中有一个freeConnection办法以前往的毗连作为参数,将毗连前往毗连池。
publicsynchronizedvoidfreeConnection(Connectioncon){
//PuttheconnectionattheendoftheVector
freeConnections.addElement(con);
checkedOut--;
notifyAll();
}
毗连被加在freeConnections向量的最初,占用的毗连数减1,挪用notifyAll()函数关照其他守候的客户如今有了一个毗连。
6、封闭
年夜多半servlet引擎供应完全的封闭办法。数据库毗连池必要失掉关照以准确地封闭一切的毗连。DBConnectionManager卖力和谐封闭事务,但毗连由各个毗连池本人卖力封闭。办法relase()由DBConnectionManager挪用。
publicsynchronizedvoidrelease(){
EnumerationallConnections=freeConnections.elements();
while(allConnections.hasMoreElements()){
Connectioncon=(Connection)allConnections.nextElement();
try{
con.close();
log("Closedconnectionforpool"+name);
}
catch(SQLExceptione){
log(e,"Cannotcloseconnectionforpool"+name);
}
}
freeConnections.removeAllElements();
}
本办法遍历freeConnections向量以封闭一切的毗连。
DBConnetionManager的机关函数是公有函数,以免其他类创立实在例。
privateDBConnectionManager(){
init();
}
DBConnetionManager的客户挪用getInstance()办法来失掉该类的单一实例的援用。
staticsynchronizedpublicDBConnectionManagergetInstance(){
if(instance==null){
instance=newDBConnectionManager();
}
clients++;
returninstance;
}
保持池利用实例
单一的实例在第一次挪用时创立,今后的挪用前往该实例的静态使用。一个计数器记录一切的客户数,直到客户开释援用。这个计数器在今后用来和谐封闭毗连池。
1、初始化
机关函数挪用一个公有的init()函数初始化对象。
privatevoidinit(){
InputStreamis=getClass().getResourceAsStream("/db.properties");
PropertiesdbProps=newProperties();
try{
dbProps.load(is);
}
catch(Exceptione){
System.err.println("Cannotreadthepropertiesfile."+"Makesuredb.propertiesisintheCLASSPATH");
return;
}
StringlogFile=dbProps.getProperty("logfile",
"DBConnectionManager.log");
try{
log=newPrintWriter(newFileWriter(logFile,true),true);
}
catch(IOExceptione){
System.err.println("Cannotopenthelogfile:"+logFile);
log=newPrintWriter(System.err);
}
loadDrivers(dbProps);
createPools(dbProps);
}
办法getResourceAsStream()是一个尺度办法,用来翻开一个内部输出文件。文件的地位取决于类加载器,而尺度的类加载器从classpath入手下手搜刮。Db.properties文件是一个Porperties格局的文件,保留在毗连池中界说的key-value对。上面一些经常使用的属性能够界说:
drivers以空格分隔的jdbc驱动程序的列表
logfile日记文件的相对路径
每一个毗连池中还利用另外一些属性。这些属性以毗连池的名字开首:
.url数据库的JDBCURL
.maxconn最年夜毗连数。0暗示无穷。
.user毗连池的用户名
.password相干的暗码
url属性是必需的,其他属性可选。用户名和暗码必需和所界说的数据库婚配。
上面是windows平台下的一个db.properties文件的例子。有一个InstantDB毗连池和一个经由过程odbc毗连的access数据库的数据源,名字叫demo。
drivers=sun.jdbc.odbc.JdbcOdbcDriverjdbc.idbDriver
logfile=D:usersrcjavaDBConnectionManagerlog.txt
idb.url=jdbc:idb:c:localjavawebserver1.1dbdb.prp
idb.maxconn=2
access.url=jdbc:odbc:demo
access.user=demo
access.password=demopw
注重,反斜线在windows平台下必需双写。
初始化办法init()创立一个Porperties对象并装载db.properties文件,然后读取日记文件属性。假如日记文件没有定名,则利用缺省的名字DBConnectionManager.log在以后目次下创立。在此情形下,一个体系毛病被记录。
办法loadDrivers()将指定的一切jdbc驱动程序注册,装载。
privatevoidloadDrivers(Propertiesprops){
StringdriverClasses=props.getProperty("drivers");
StringTokenizerst=newStringTokenizer(driverClasses);
while(st.hasMoreElements()){
StringdriverClassName=st.nextToken().trim();
try{
Driverdriver=(Driver)
Class.forName(driverClassName).newInstance();
DriverManager.registerDriver(driver);
drivers.addElement(driver);
log("RegisteredJDBCdriver"+driverClassName);
}
catch(Exceptione){
log("CannotregisterJDBCdriver:"+driverClassName+",Exception:"+e);
}
}
}
loadDrivers()利用StringTokenizer将dirvers属性分红独自的driver串,并将每一个驱动程序装进java假造机。驱动程序的实例在JDBC的DriverManager中注册,并到场一个公有的向量drivers中。向量drivers用来封闭和刊出一切的驱动程序。
然后,DBConnectionPool对象由公有办法createPools()创立。
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(poolName+".url");
if(url==null){
log("NoURLspecifiedfor"+poolName);
continue;
}
Stringuser=props.getProperty(poolName+".user");
Stringpassword=props.getProperty(poolName+".password");
Stringmaxconn=props.getProperty(poolName+".maxconn","0");
intmax;
try{
max=Integer.valueOf(maxconn).intValue();
}
catch(NumberFormatExceptione){
log("Invalidmaxconnvalue"+maxconn+"for"+poolName);
max=0;
}
DBConnectionPoolpool=newDBConnectionPool(poolName,url,user,password,max);
pools.put(poolName,pool);
log("Initializedpool"+poolName);
}
}
}
一个列举对象保留一切的属性名,假如属性名带有.url开头,则暗示是一个毗连池对象必要被实例化。创立的毗连池对象保留在一个Hashtable实例变量中。毗连池名字作为索引,毗连池对象作为值。
2、失掉和前往毗连
DBConnectionManager供应getConnection()办法和freeConnection办法,这些办法有客户程序利用。一切的办法以毗连池名字所参数,并挪用特定的毗连池对象。
publicConnectiongetConnection(Stringname){
DBConnectionPoolpool=(DBConnectionPool)pools.get(name);
if(pool!=null){
returnpool.getConnection();
}
returnnull;
}
publicConnectiongetConnection(Stringname,longtime){
DBConnectionPoolpool=(DBConnectionPool)pools.get(name);
if(pool!=null){
returnpool.getConnection(time);
}
returnnull;
}
publicvoidfreeConnection(Stringname,Connectioncon){
DBConnectionPoolpool=(DBConnectionPool)pools.get(name);
if(pool!=null){
pool.freeConnection(con);
}
}
3、封闭
最初,由一个release()办法,用来无缺地封闭毗连池。每一个DBConnectionManager客户必需挪用getInstance()办法援用。有一个计数器跟踪客户的数目。办法release()在客户封闭时挪用,手艺器减1。当最初一个客户开释,DBConnectionManager封闭一切的毗连池。
publicsynchronizedvoidrelease(){
//Waituntilcalledbythelastclient
if(--clients!=0){
return;
}
EnumerationallPools=pools.elements();
while(allPools.hasMoreElements()){
DBConnectionPoolpool=(DBConnectionPool)allPools.nextElement();
pool.release();
}
EnumerationallDrivers=drivers.elements();
while(allDrivers.hasMoreElements()){
Driverdriver=(Driver)allDrivers.nextElement();
try{
DriverManager.deregisterDriver(driver);
log("DeregisteredJDBCdriver"+driver.getClass().getName());
}
catch(SQLExceptione){
log(e,"CannotderegisterJDBCdriver:"+driver.getClass().getName());
}
}
}
当一切毗连池封闭,一切jdbc驱动程序也被刊出。
<P> 保持池的感化
如今我们分离DBConnetionManager和DBConnectionPool类来说解servlet中毗连池的利用:
1、起首复杂先容一下Servlet的性命周期:
ServletAPI界说的servlet性命周期以下:
1、Servlet被创立然后初始化(init()办法)。
2、为0个或多个客户挪用供应服务(service()办法)。
3、Servlet被烧毁,内存被接纳(destroy()办法)。
2、servlet中利用毗连池的实例
利用毗连池的servlet有三个阶段的典范体现是:
1.在init()中,挪用DBConnectionManager.getInstance()然后将前往的援用保留在实例变量中。
2.在sevice()中,挪用getConnection(),实行一系列数据库操纵,然后挪用freeConnection()偿还毗连。
3.在destroy()中,挪用release()来开释一切的资本,并封闭一切的毗连。
上面的例子演示怎样利用毗连池。
importjava.io.*;
importjava.sql.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassTestServletextendsHttpServlet{
privateDBConnectionManagerconnMgr;
publicvoidinit(ServletConfigconf)throwsServletException{
super.init(conf);
connMgr=DBConnectionManager.getInstance();
}
publicvoidservice(HttpServletRequestreq,HttpServletResponseres)
throwsIOException{
res.setContentType("text/html");
PrintWriterout=res.getWriter();
Connectioncon=connMgr.getConnection("idb");
if(con==null){
out.println("Cantgetconnection");
return;
}
ResultSetrs=null;
ResultSetMetaDatamd=null;
Statementstmt=null;
try{
stmt=con.createStatement();
rs=stmt.executeQuery("SELECT*FROMEMPLOYEE");
md=rs.getMetaData();
out.println("Employeedata");
while(rs.next()){
out.println("");
for(inti=1;i<md.getColumnCount();i++){
out.print(rs.getString(i)+",");
}
}
stmt.close();
rs.close();
}
catch(SQLExceptione){
e.printStackTrace(out);
}
connMgr.freeConnection("idb",con);
}
publicvoiddestroy(){
connMgr.release();
super.destroy();
}
}
比如模式、敏捷方法什么的,这些思想好,但是实施的人没有理解而且没有正确运用这些知识导致了开发周期的延长。比如说对象,通过getName()方法不能获取对象的名字。 |
|