所属类别:JSP
文章作者:未知
特别推荐:免费发布信息 承包关键词~~抢爆了!HOT!
title:JSP分页技术实现summary:使用工具类实现通用分页处理author:evan_zhaoemail:evan_zhao@hotmail.com
目前比较广泛使用的分页方式是将查询结果缓存在HttpSession或有状态bean中,翻页的时候从缓存中取出一页数据显示。这种方法有两个主要的缺点:一是用户可能看到的是过期数据;二是如果数据量非常大时第一次查询遍历结果集会耗费很长时间,并且缓存的数据也会占用大量内存,效率明显下降。
其它常见的方法还有每次翻页都查询一次数据库,从ResultSet中只取出一页数据(使用rs.last();rs.getRow()获得总计录条数,使用rs.absolute()定位到本页起始记录)。这种方式在某些数据库(如oracle)的JDBC实现中差不多也是需要遍历所有记录,实验证明在记录数很大时速度非常慢。
至于缓存结果集ResultSet的方法则完全是一种错误的做法。因为ResultSet在Statement或Connection关闭时也会被关闭,如果要使ResultSet有效势必长时间占用数据库连接。
因此比较好的分页做法应该是每次翻页的时候只从数据库里检索页面大小的块区的数据。这样虽然每次翻页都需要查询数据库,但查询出的记录数很少,网络传输数据量不大,如果使用连接池更可以略过最耗时的建立数据库连接过程。而在数据库端有各种成熟的优化技术用于提高查询速度,比在应用服务器层做缓存有效多了。
在oracle数据库中查询结果的行号使用伪列ROWNUM表示(从1开始)。例如select*fromemployeewhererownum<10返回前10条记录。但因为rownum是在查询之后排序之前赋值的,所以查询employee按birthday排序的第100到120条记录应该这么写:[pre]select*from(selectmy_table.*,rownumasmy_rownumfrom(selectname,birthdayfromemployeeorderbybirthday)my_tablewhererownum<120)wheremy_rownum>=100[/pre]
mySQL可以使用LIMIT子句:
selectname,birthdayfromemployeeorderbybirthdayLIMIT99,20
DB2有rownumber()函数用于获取当前行数。
SQLServer没研究过,可以参考这篇文章:http://www.csdn.net/develop/article/18/18627.shtm
在Web程序中分页会被频繁使用,但分页的实现细节却是编程过程中比较麻烦的事情。大多分页显示的查询操作都同时需要处理复杂的多重查询条件,sql语句需要动态拼接组成,再加上分页需要的记录定位、总记录条数查询以及查询结果的遍历、封装和显示,程序会变得很复杂并且难以理解。因此需要一些工具类简化分页代码,使程序员专注于业务逻辑部分。下面是我设计的两个工具类:
PagedStatement封装了数据库连接、总记录数查询、分页查询、结果数据封装和关闭数据库连接等操作,并使用了PreparedStatement支持动态设置参数。
RowSetPage参考PetStore的pagebypageiterator模式,设计RowSetPage用于封装查询结果(使用OracleCachedRowSet缓存查询出的一页数据,关于使用CachedRowSet封装数据库查询结果请参考JSP页面查询显示常用模式)以及当前页码、总记录条数、当前记录数等信息,并且可以生成简单的HTML分页代码。
PagedStatement查询的结果封装成RowsetPage。
下面是简单的使用示例://DAO查询数据部分代码:…publicRowSetPagegetEmployee(Stringgender,intpageNo)throwsException{Stringsql="selectemp_id,emp_code,user_name,real_namefromemployeewheregender=?";//使用Oracle数据库的分页查询实现,每页显示5条PagedStatementpst=newPagedStatementOracleImpl(sql,pageNo,5);pst.setString(1,gender);returnpst.executeQuery();}//Servlet处理查询请求部分代码:…intpageNo;try{//可以通过参数pageno获得用户选择的页码pageNo=Integer.parseInt(request.getParameter("pageno"));}catch(Exceptionex){//默认为第一页pageNo=1;}Stringgender=request.getParameter("gender");request.setAttribute("empPage",myBean.getEmployee(gender,pageNo));…//JSP显示部分代码<%@pageimport="page.RowSetPage"%>…functiondoQuery(){form1.actionType.value="doQuery";form1.submit();}…性别:"><%RowSetPageempPage=(RowSetPage)request.getAttribute("empPage");if(empPage==null)empPage=RowSetPage.EMPTY_PAGE;%>…ID代码用户名姓名<%javax.sql.RowSetempRS=(javax.sql.RowSet)empPage.getRowSet();if(empRS!=null)while(empRS.next()){%><%=empRS.getString("EMP_ID")%><%=empRS.getString("EMP_CODE")%><%=empRS.getString("USER_NAME")%><%=empRS.getString("REAL_NAME")%><%}//endwhile%><%//显示总页数和当前页数(pageno)以及分页代码。//此处doQuery为页面上提交查询动作的javascript函数名,pageno为标识当前页码的参数名%><%=empPage.getHTML("doQuery","pageno")%>
效果如图:
因为分页显示一般都会伴有查询条件和查询动作,页面应已经有校验查询条件和提交查询的javascript方法(如上面的doQuery),所以RowSetPage.getHTML()生成的分页代码在用户选择新页码时直接回调前面的处理提交查询的javascript方法。注意在显示查询结果的时候上次的查询条件也需要保持,如">。同时由于页码的参数名可以指定,因此也支持在同一页面中有多个分页区。
另一种分页代码实现是生成每一页的URL,将查询参数和页码作为QueryString附在URL后面。这种方法的缺陷是在查询条件比较复杂时难以处理,并且需要指定处理查询动作的servlet,可能不适合某些定制的查询操作。
如果对RowSetPage.getHTML()生成的默认分页代码不满意可以编写自己的分页处理代码,RowSetPage提供了很多getter方法用于获取相关信息(如当前页码、总页数、总记录数和当前记录数等)。
在实际应用中可以将分页查询和显示做成jsptaglib,进一步简化JSP代码,屏蔽JavaCode。附:分页工具类的源代码,有注释,应该很容易理解。1.Page.java2.RowSetPage.java(RowSetPage继承Page)3.PagedStatement.java4.PagedStatementOracleImpl.java(PagedStatementOracleImpl继承PagedStatement)您可以任意使用这些源代码,但必须保留authorevan_zhao@hotmail.com字样///////////////////////////////////////Page.java//author:evan_zhao@hotmail.com/////////////////////////////////////packagepage;importjava.util.List;importjava.util.ArrayList;importjava.util.Collection;importjava.util.Collections;/***Title:分页对象*Description:用于包含数据及分页信息的对象*Page类实现了用于显示分页信息的基本方法,但未指定所含数据的类型,*可根据需要实现以特定方式组织数据的子类,*如RowSetPage以RowSet封装数据,ListPage以List封装数据*Copyright:Copyright(c)2002*@authorevan_zhao@hotmail.com*@version1.0*/publicclassPageimplementsjava.io.Serializable{publicstaticfinalPageEMPTY_PAGE=newPage();publicstaticfinalintDEFAULT_PAGE_SIZE=20;publicstaticfinalintMAX_PAGE_SIZE=9999;privateintmyPageSize=DEFAULT_PAGE_SIZE;privateintstart;privateintavaCount,totalSize;privateObjectdata;privateintcurrentPageno;privateinttotalPageCount;/***默认构造方法,只构造空页*/protectedPage(){this.init(0,0,0,DEFAULT_PAGE_SIZE,newObject());}/***分页数据初始方法,由子类调用*@paramstart本页数据在数据库中的起始位置*@paramavaCount本页包含的数据条数*@paramtotalSize数据库中总记录条数*@parampageSize本页容量*@paramdata本页包含的数据*/protectedvoidinit(intstart,intavaCount,inttotalSize,intpageSize,Objectdata){this.avaCount=avaCount;this.myPageSize=pageSize;this.start=start;this.totalSize=totalSize;this.data=data;//System.out.println("avaCount:"+avaCount);//System.out.println("totalSize:"+totalSize);if(avaCount>totalSize){//thrownewRuntimeException("记录条数大于总条数?!");}this.currentPageno=(start-1)/pageSize+1;this.totalPageCount=(totalSize+pageSize-1)/pageSize;if(totalSize==0&&avaCount==0){this.currentPageno=1;this.totalPageCount=1;}//System.out.println("StartIndextoPageNo:"+start+"-"+currentPageno);}publicObjectgetData(){returnthis.data;}/***取本页数据容量(本页能包含的记录数)*@return本页能包含的记录数*/publicintgetPageSize(){returnthis.myPageSize;}/***是否有下一页*@return是否有下一页*/publicbooleanhasNextPage(){/*if(avaCount==0&&totalSize==0){returnfalse;}return(start+avaCount-1)<totalSize;*/return(this.getCurrentPageNo()1;*/return(this.getCurrentPageNo()>1);}/***获取当前页第一条数据在数据库中的位置*@return*/publicintgetStart(){returnstart;}/***获取当前页最后一条数据在数据库中的位置*@return*/publicintgetEnd(){intend=this.getStart()+this.getSize()-1;if(end<0){end=0;}returnend;}/***获取上一页第一条数据在数据库中的位置*@return记录对应的rownum*/publicintgetStartOfPreviousPage(){returnMath.max(start-myPageSize,1);}/***获取下一页第一条数据在数据库中的位置*@return记录对应的rownum*/publicintgetStartOfNextPage(){returnstart+avaCount;}/***获取任一页第一条数据在数据库中的位置,每页条数使用默认值*@parampageNo页号*@return记录对应的rownum*/publicstaticintgetStartOfAnyPage(intpageNo){returngetStartOfAnyPage(pageNo,DEFAULT_PAGE_SIZE);}/***获取任一页第一条数据在数据库中的位置*@parampageNo页号*@parampageSize每页包含的记录数*@return记录对应的rownum*/publicstaticintgetStartOfAnyPage(intpageNo,intpageSize){intstartIndex=(pageNo-1)*pageSize+1;if(startIndex<1)startIndex=1;//System.out.println("PageNotoStartIndex:"+pageNo+"-"+startIndex);returnstartIndex;}/***取本页包含的记录数*@return本页包含的记录数*/publicintgetSize(){returnavaCount;}/***取数据库中包含的总记录数*@return数据库中包含的总记录数*/publicintgetTotalSize(){returnthis.totalSize;}/***取当前页码*@return当前页码*/publicintgetCurrentPageNo(){returnthis.currentPageno;}/***取总页码*@return总页码*/publicintgetTotalPageCount(){returnthis.totalPageCount;}/****@paramqueryJSFunctionName实现分页的JS脚本名字,页码变动时会自动回调该方法*@parampageNoParamName页码参数名称*@return*/publicStringgetHTML(StringqueryJSFunctionName,StringpageNoParamName){if(getTotalPageCount()<1){return"";}if(queryJSFunctionName==nullqueryJSFunctionName.trim().length()<1){queryJSFunctionName="gotoPage";}if(pageNoParamName==nullpageNoParamName.trim().length()<1){pageNoParamName="pageno";}StringgotoPage="_"+queryJSFunctionName;StringBufferhtml=newStringBuffer("\n");html.append("\n").append("function").append(gotoPage).append("(pageNo){\n").append("varcurPage=1;\n").append("try{curPage=document.all[\"").append(pageNoParamName).append("\"].value;\n").append("document.all[\"").append(pageNoParamName).append("\"].value=pageNo;\n").append("").append(queryJSFunctionName).append("(pageNo);\n").append("returntrue;\n").append("}catch(e){\n")//.append("try{\n")//.append("document.forms[0].submit();\n")//.append("}catch(e){\n").append("alert('尚未定义查询方法:function").append(queryJSFunctionName).append("()');\n").append("document.all[\"").append(pageNoParamName).append("\"].value=curPage;\n").append("returnfalse;\n")//.append("}\n").append("}\n").append("}").append("\n").append("");html.append("\n").append("\n").append("\n");html.append("共").append(getTotalPageCount()).append("页").append("[").append(getStart()).append("..").append(getEnd()).append("/").append(this.getTotalSize()).append("]\n").append("\n").append("\n");if(hasPreviousPage()){html.append("[上一页]\n");}html.append("第").append("\n");Stringselected="selected";for(inti=1;i<=getTotalPageCount();i++){if(i==getCurrentPageNo())selected="selected";elseselected="";html.append("").append(i).append("\n");}if(getCurrentPageNo()>getTotalPageCount()){html.append("").append(getCurrentPageNo()).append("\n");}html.append("页\n");if(hasNextPage()){html.append("[下一页]\n");}html.append("\n");returnhtml.toString();}}///////////////////////////////////////RowSetPage.java//author:evan_zhao@hotmail.com/////////////////////////////////////packagepage;importjavax.sql.RowSet;/***Title:RowSetPage*Description:使用RowSet封装数据的分页对象*Copyright:Copyright(c)2003*@authorevan_zhao@hotmail.com*@version1.0*/publicclassRowSetPageextendsPage{privatejavax.sql.RowSetrs;/***空页*/publicstaticfinalRowSetPageEMPTY_PAGE=newRowSetPage();/***默认构造方法,创建空页*/publicRowSetPage(){this(null,0,0);}/***构造分页对象*@paramcrs包含一页数据的OracleCachedRowSet*@paramstart该页数据在数据库中的起始位置*@paramtotalSize数据库中包含的记录总数*/publicRowSetPage(RowSetcrs,intstart,inttotalSize){this(crs,start,totalSize,Page.DEFAULT_PAGE_SIZE);}/***构造分页对象*@paramcrs包含一页数据的OracleCachedRowSet*@paramstart该页数据在数据库中的起始位置*@paramtotalSize数据库中包含的记录总数*@pageSize本页能容纳的记录数*/publicRowSetPage(RowSetcrs,intstart,inttotalSize,intpageSize){try{intavaCount=0;if(crs!=null){crs.beforeFirst();if(crs.next()){crs.last();avaCount=crs.getRow();}crs.beforeFirst();}rs=crs;super.init(start,avaCount,totalSize,pageSize,rs);}catch(java.sql.SQLExceptionsqle){thrownewRuntimeException(sqle.toString());}}/***取分页对象中的记录数据*/publicjavax.sql.RowSetgetRowSet(){returnrs;}}///////////////////////////////////////PagedStatement.java//author:evan_zhao@hotmail.com/////////////////////////////////////packagepage;importfoo.DBUtil;importjava.math.BigDecimal;importjava.util.List;importjava.util.Iterator;importjava.util.Collections;importjava.sql.Connection;importjava.sql.SQLException;importjava.sql.ResultSet;importjava.sql.Statement;importjava.sql.PreparedStatement;importjava.sql.Timestamp;importjavax.sql.RowSet;/***Title:分页查询*Description:根据查询语句和页码查询出当页数据*Copyright:Copyright(c)2002*@authorevan_zhao@hotmail.com*@version1.0*/publicabstractclassPagedStatement{publicfinalstaticintMAX_PAGE_SIZE=Page.MAX_PAGE_SIZE;protectedStringcountSQL,querySQL;protectedintpageNo,pageSize,startIndex,totalCount;protectedjavax.sql.RowSetrowSet;protectedRowSetPagerowSetPage;privateListboundParams;/***构造一查询出所有数据的PageStatement*@paramsqlquerysql*/publicPagedStatement(Stringsql){this(sql,1,MAX_PAGE_SIZE);}/***构造一查询出当页数据的PageStatement*@paramsqlquerysql*@parampageNo页码*/publicPagedStatement(Stringsql,intpageNo){this(sql,pageNo,Page.DEFAULT_PAGE_SIZE);}/***构造一查询出当页数据的PageStatement,并指定每页显示记录条数*@paramsqlquerysql*@parampageNo页码*@parampageSize每页容量*/publicPagedStatement(Stringsql,intpageNo,intpageSize){this.pageNo=pageNo;this.pageSize=pageSize;this.startIndex=Page.getStartOfAnyPage(pageNo,pageSize);this.boundParams=Collections.synchronizedList(newjava.util.LinkedList());this.countSQL="selectcount(*)from("+sql+")";this.querySQL=intiQuerySQL(sql,this.startIndex,pageSize);}/***生成查询一页数据的sql语句*@paramsql原查询语句*@startIndex开始记录位置*@size需要获取的记录数*/protectedabstractStringintiQuerySQL(Stringsql,intstartIndex,intsize);/***使用给出的对象设置指定参数的值*@paramindex第一个参数为1,第二个为2,。。。*@paramobj包含参数值的对象*/publicvoidsetObject(intindex,Objectobj)throwsSQLException{BoundParambp=newBoundParam(index,obj);boundParams.remove(bp);boundParams.add(bp);}/***使用给出的对象设置指定参数的值*@paramindex第一个参数为1,第二个为2,。。。*@paramobj包含参数值的对象*@paramtargetSqlType参数的数据库类型*/publicvoidsetObject(intindex,Objectobj,inttargetSqlType)throwsSQLException{BoundParambp=newBoundParam(index,obj,targetSqlType);boundParams.remove(bp);boundParams.add(bp);}/***使用给出的对象设置指定参数的值*@paramindex第一个参数为1,第二个为2,。。。*@paramobj包含参数值的对象*@paramtargetSqlType参数的数据库类型(常量定义在java.sql.Types中)*@paramscale精度,小数点后的位数*(只对targetSqlType是Types.NUMBER或Types.DECIMAL有效,其它类型则忽略)*/publicvoidsetObject(intindex,Objectobj,inttargetSqlType,intscale)throwsSQLException{BoundParambp=newBoundParam(index,obj,targetSqlType,scale);boundParams.remove(bp);boundParams.add(bp);}/***使用给出的字符串设置指定参数的值*@paramindex第一个参数为1,第二个为2,。。。*@paramstr包含参数值的字符串*/publicvoidsetString(intindex,Stringstr)throwsSQLException{BoundParambp=newBoundParam(index,str);boundParams.remove(bp);boundParams.add(bp);}/***使用给出的字符串设置指定参数的值*@paramindex第一个参数为1,第二个为2,。。。*@paramtimestamp包含参数值的时间戳*/publicvoidsetTimestamp(intindex,Timestamptimestamp)throwsSQLException{BoundParambp=newBoundParam(index,timestamp);boundParams.remove(bp);boundParams.add(bp);}/***使用给出的整数设置指定参数的值*@paramindex第一个参数为1,第二个为2,。。。*@paramvalue包含参数值的整数*/publicvoidsetInt(intindex,intvalue)throwsSQLException{BoundParambp=newBoundParam(index,newInteger(value));boundParams.remove(bp);boundParams.add(bp);}/***使用给出的长整数设置指定参数的值*@paramindex第一个参数为1,第二个为2,。。。*@paramvalue包含参数值的长整数*/publicvoidsetLong(intindex,longvalue)throwsSQLException{BoundParambp=newBoundParam(index,newLong(value));boundParams.remove(bp);boundParams.add(bp);}/***使用给出的双精度浮点数设置指定参数的值*@paramindex第一个参数为1,第二个为2,。。。*@paramvalue包含参数值的双精度浮点数*/publicvoidsetDouble(intindex,doublevalue)throwsSQLException{BoundParambp=newBoundParam(index,newDouble(value));boundParams.remove(bp);boundParams.add(bp);}/***使用给出的BigDecimal设置指定参数的值*@paramindex第一个参数为1,第二个为2,。。。*@parambd包含参数值的BigDecimal*/publicvoidsetBigDecimal(intindex,BigDecimalbd)throwsSQLException{BoundParambp=newBoundParam(index,bd);boundParams.remove(bp);boundParams.add(bp);}privatevoidsetParams(PreparedStatementpst)throwsSQLException{if(pst==nullthis.boundParams==nullthis.boundParams.size()==0)return;BoundParamparam;for(Iteratoritr=this.boundParams.iterator();itr.hasNext();){param=(BoundParam)itr.next();if(param==null)continue;if(param.sqlType==java.sql.Types.OTHER){pst.setObject(param.index,param.value);}else{pst.setObject(param.index,param.value,param.sqlType,param.scale);}}}/***执行查询取得一页数据,执行结束后关闭数据库连接*@returnRowSetPage*@throwsSQLException*/publicRowSetPageexecuteQuery()throwsSQLException{System.out.println("executeQueryUsingPreparedStatement");Connectionconn=DBUtil.getConnection();PreparedStatementpst=null;ResultSetrs=null;try{pst=conn.prepareStatement(this.countSQL);setParams(pst);rs=pst.executeQuery();if(rs.next()){totalCount=rs.getInt(1);}else{totalCount=0;}rs.close();pst.close();if(totalCount<1)returnRowSetPage.EMPTY_PAGE;pst=conn.prepareStatement(this.querySQL);System.out.println(querySQL);pst.setFetchSize(this.pageSize);setParams(pst);rs=pst.executeQuery();//rs.setFetchSize(pageSize);this.rowSet=populate(rs);rs.close();rs=null;pst.close();pst=null;this.rowSetPage=newRowSetPage(this.rowSet,startIndex,totalCount,pageSize);returnthis.rowSetPage;}catch(SQLExceptionsqle){//System.out.println("executeQuerySQLException");sqle.printStackTrace();throwsqle;}catch(Exceptione){e.printStackTrace();thrownewRuntimeException(e.toString());}finally{//System.out.println("executeQueryfinally");DBUtil.close(rs,pst,conn);}}/***将ResultSet数据填充进CachedRowSet*/protectedabstractRowSetpopulate(ResultSetrs)throwsSQLException;/***取封装成RowSet查询结果*@returnRowSet*/publicjavax.sql.RowSetgetRowSet(){returnthis.rowSet;}/***取封装成RowSetPage的查询结果*@returnRowSetPage*/publicRowSetPagegetRowSetPage(){returnthis.rowSetPage;}/***关闭数据库连接*/publicvoidclose(){//因为数据库连接在查询结束或发生异常时即关闭,此处不做任何事情//留待扩充。}privateclassBoundParam{intindex;Objectvalue;intsqlType;intscale;publicBoundParam(intindex,Objectvalue){this(index,value,java.sql.Types.OTHER);}publicBoundParam(intindex,Objectvalue,intsqlType){this(index,value,sqlType,0);}publicBoundParam(intindex,Objectvalue,intsqlType,intscale){this.index=index;this.value=value;this.sqlType=sqlType;this.scale=scale;}publicbooleanequals(Objectobj){if(obj!=null&&this.getClass().isInstance(obj)){BoundParambp=(BoundParam)obj;if(this.index==bp.index)returntrue;}returnfalse;}}}///////////////////////////////////////PagedStatementOracleImpl.java//author:evan_zhao@hotmail.com/////////////////////////////////////packagepage;importjava.sql.ResultSet;importjava.sql.SQLException;importjavax.sql.RowSet;importoracle.jdbc.rowset.OracleCachedRowSet;/***Title:分页查询Oracle数据库实现*Copyright:Copyright(c)2002*@authorevan_zhao@hotmail.com*@version1.0*/publicclassPagedStatementOracleImplextendsPagedStatement{/***构造一查询出所有数据的PageStatement*@paramsqlquerysql*/publicPagedStatementOracleImpl(Stringsql){super(sql);}/***构造一查询出当页数据的PageStatement*@paramsqlquerysql*@parampageNo页码*/publicPagedStatementOracleImpl(Stringsql,intpageNo){super(sql,pageNo);}/***构造一查询出当页数据的PageStatement,并指定每页显示记录条数*@paramsqlquerysql*@parampageNo页码*@parampageSize每页容量*/publicPagedStatementOracleImpl(Stringsql,intpageNo,intpageSize){super(sql,pageNo,pageSize);}/***生成查询一页数据的sql语句*@paramsql原查询语句*@startIndex开始记录位置*@size需要获取的记录数*/protectedStringintiQuerySQL(Stringsql,intstartIndex,intsize){StringBufferquerySQL=newStringBuffer();if(size!=super.MAX_PAGE_SIZE){querySQL.append("select*from(selectmy_table.*,rownumasmy_rownumfrom(").append(sql).append(")my_tablewhererownum<").append(startIndex+size).append(")wheremy_rownum>=").append(startIndex);}else{querySQL.append("select*from(selectmy_table.*,rownumasmy_rownumfrom(").append(sql).append(")my_table").append(")wheremy_rownum>=").append(startIndex);}returnquerySQL.toString();}/***将ResultSet数据填充进CachedRowSet*/protectedRowSetpopulate(ResultSetrs)throwsSQLException{OracleCachedRowSetocrs=newOracleCachedRowSet();ocrs.populate(rs);returnocrs;}}相关连接:
JSP页面查询显示常用模式,介绍查询结果集封装的几种常用模式。本程序使用了其中部分代码
RowSet规范原来是JDBC(TM)2.0OptionalPackage的一部分,现在已经并入JDBC3.0规范,并且将成为J2SE1.5的组成部分。
关于RowSet的实现各个数据库的jdbcdriver应该都有提供,oracle实现可以到http://otn.oracle.com/software/tech/java/sqlj_jdbc/content.html下载(AdditionalRowSetsupport)
Sun也提供了RowSet的参考实现,应该可以支持大多数数据库:http://java.sun.com/products/jdbc/download.html
PetStore是Sun关于J2EE设计模式的一个示例程序。关闭本页
相关信息· 速成!全面了解Vista系统安全机制
· device_driver结构体(2.6.23)
· 根据域名获得IP地址列表(学习C
· 微软SQL Server中国研发中心成立
69657
75768
