数据库

位置:IT落伍者 >> 数据库 >> 浏览文章

高效SQL分页存储过程(2)


发布日期:2021年04月09日
 
高效SQL分页存储过程(2)

Book类负责查询数据库把结果放到一个ArrayList中

package bean;

import javasql*;

import javautilArrayList;

public class Book {

private String bookname;

private String author;

private String price;

public Book(String nameString authorString price) {

thisbookname=name;

thisauthor=author;

thisprice=price;

}

public void setBookname(String bookname) {

thisbookname=bookname;

}

public void setAuthor(String Author) {

thisauthor=author;

}

public void setPrice(String price) {

thisprice=price;

}

public String getBookname() {

return bookname;

}

public String getAuthor() {

return author;

}

public String getPrice() {

return price;

}

public static ArrayList getAllBook() throws Exception {

String sql=select * from book;

SqlBean sq=new SqlBean();

ArrayList arrayList=new ArrayList();

try

{

ResultSet resultSet=sqselect(sql);

while(resultSetnext()) {

String name=resultSetgetString(name);

String author=resultSetgetString(author);

String price=resultSetgetString(price);

Book book=new Book(nameauthorprice);

arrayListadd(book);

}

resultSetclose();

}

catch(SQLException e)

{

Systemoutprintln(数据库错误+etoString());

}

return arrayList;

}

}

这个是SqlBook负责和数据库建立一个连接的Bean

package bean;

import javasqlConnection;

import javasqlDriverManager;

import javasqlResultSet;

import javasqlStatement;

public class SqlBean {

String url=jdbc:microsoft:sqlserver://localhost:;DatabaseName=eBookStore;

Connection con=null;

Statement sta=null;

public SqlBean() {

try

{

ClassforName(commicrosoftjdbcsqlserverSQLServerDriver);

con=DriverManagergetConnection(urlsa);

sta=concreateStatement();

}

catch(Exception e)

{

Systemoutprintln(连接错误+etoString());

}

}

public ResultSet select(String selects) throws Exception

{

return staexecuteQuery(selects);

}

}

…………………………………………………………………………

这个是负责显示分页的JSP页pagetestjsp

<%@ taglib uri=/WEBINF/strutshtmltld prefix=html%>

<%@ taglib uri=/WEBINF/strutsbeantld prefix=bean%>

<%@ taglib uri=/WEBINF/strutslogictld prefix=logic%>

<%@ page contentType=text/html;charset=gb%>

<html:html locale=true>

<head>

</head>

<body>

<table border=>

<tr><th>书名</th><th>作者</th><th>价格</th></tr>

<logic:present name=result>

<logic:iterate id=book name=result type=beanBook>

<logic:present name=book>

<tr>

<td><bean:write name=book property=bookname/></td>

<td><bean:write name=book property=author/></td>

<td><bean:write name=book property=price/></td>

</tr>

</logic:present>

</logic:iterate>

</logic:present>

</table>

<logic:present name=page>

<logic:equal name=page property=hasNextPage value=true>

<html:link page=/hahado?action=nextPage>nextPage</html:link>

</logic:equal>

<logic:equal name=page property=hasPreviousPage value=true>

<html:link page=/hahado?action=previousPage>previousPage</html:link>

</logic:equal>

共分<bean:write name=page property=totalPages/>页显示当前是

<bean:write name=page property=currentPage/>页

</logic:present>

</body>

</html:html>

这个是首页的JSP页面只有一个连接提交一个hahado的请求

<%@ taglib uri=/WEBINF/strutshtmltld prefix=html%>

<%@ page contentType=text/html;charset=gb language=java%>

<html:html>

<head>

</head>

<body>

<html:link action=hahado>GotoPage</html:link>

</body>

</html:html>

struts下的分页代码

Struts分页的一个实现

在Web应用程序里分页总让我们开发人员感到很头疼倒不是因为技术上有多么困难只是本来和业务没有太多关系的这么一个问题你却得花不少功夫来处理要是稍不留神时不时出点问题就更郁闷了我现在做的一个项目也到了该处理分页的时候了感觉以前处理得都不好所以这次有所改变基本目标是在现有(未分页)的代码基础上尽量少做修改并且同样的代码可以应用于不同模块的分页以下就是我用的方法

首先考虑分页绝大多数发生在列表时组合查询时也需要用到在我的项目里列表的Action一般名字为ListXXXActioin例如客户列表是ListClientsAction等等在未分页前ListXXXAction里会把所有的对象取出通过requestsetAttribute()放在request里然后将请求转向到列表的jsp(例如listClientsjsp)显示出来(你可能会说不要在Action里放业务逻辑但现在这不是我们考虑的重点)而分页后我们只取用户请求页对应的那些对象为了最大限度的达到代码重用我做了以下工作

新建一个Pager类该类有beginPageendPagecurrentPagepageSize和total等int类型的属性分别代表开始页结束页当前页每页记录数和总记录数它主要是让jsp页面显示页导航使用的请注意currentPage属性是从开始的

新建一个AbstractListActioin类并让所有ListXXXAction都继承它在这个类里覆盖execute()方法可以在这里判断权限等等并在判断权限通过后执行一个abstract的act()方法这个act()由ListXXXAction来实现

在AbstractListAction里增加getPage()方法用来从request得到用户请求的页码(若未请求则认为是第页)

protected int getPage(HttpServletRequest request) {

String p = requestgetParameter(p);

if (p == null)

return ;

else

try {

return IntegerparseInt(p);

} catch (NumberFormatException e) {

return ;

}

}

在AbstractListAction里增加makePager()方法用来向request里增加一个Pager类的实例供jsp页面显示页导航

protected Pager makePager(HttpServletRequest request int total) {

Pager pager=new Pager();

pagersetTotal(total);

pagersetPageSize(ConfiggetInstance()getPageSize());

pagersetBeginPage();

pagersetEndPage(((pagergetTotal()) ) / pagergetPageSize() + );

pagersetCurrentPage(getPage(request));

return pager;

}

注意在我的项目里每页记录数是写在配置文件里的如果你没有配置文件上面第行setPageSize()的参数直接填数字即可例如pagersetPageSize();

这样所有的ListXXXAction都可以使用getPage()得到请求的页码并且能够方便的通过makePager()构造需要放在request里的pager对象了现在要在从数据库取数据的代码上再做一些修改即只取所需要的那一部分数据由于我的项目中使用了Hibernate所以这个修改也不是很困难未分页前在我的ListClientsAction里是通过构造一个Query来得到全部Client的现在只要在构造这个Query后再加两句(setMaxResults和setFirstResult)即可

Query query = ;//构造query的语句

int total = ;//得到总记录数

Pager pager = makePager(request total);//调用父类中的方法构造一个Pager实例

querysetMaxResults(pagergetPageSize());//设置每页记录数

querysetFirstResult(pagergetCurrentPage() * pagergetPageSize()); //设置开始位置

requestsetAttribute(PagerclassgetName() pager);//把pager放在request里

requestsetAttribute(ClientclassgetName() querylist());

目前存在一个问题就是在上面代码的第二句中应该是获得总记录数但我暂时没有特别好的办法不得到全部对象而直接得到记录数只能很恐怖的用int total = querylist()size();汗……

最后我写了一个页导航的jsp页面pagerjsp供各个显示列表的jsp来include代码如下

<%Pager pager=(Pager)requestgetAttribute(PagerclassgetName());%>

<table width=% border= align=center cellpadding= cellspacing= bgcolor=#CCCCCC>

<tr>

<td bgcolor=#EEEEEE align=right>

<bean:message key=promptpager arg=<%=+pagergetTotal()%>/>

[

<%

String url=requestgetRequestURL()toString();

for(int i=pagergetBeginPage();i<pagergetEndPage();i++){

if(i==pagergetCurrentPage()){

%>

<%=(i+)%>

<%}else{

String qs=requestgetQueryString()==null?:requestgetQueryString();

String op = p=+pagergetCurrentPage();//Original page parameter expression

String np = p=+i;//New expression

if(qsindexOf(op)==)

qs=np+&+qs;

qs=qsreplaceAll(opnp);

%>

<a <%=url+?+qs%>><%=(i+)%></a>

<%}%>

<%if(i<pagergetEndPage()){%>

&nbsp;

<%}%>

<%}%>

]

</td></tr>

</table>

我觉得有必要解释一下在上面的代码中关于每一页对应的url是这样处理取requestgetRequestURL()toString()和requestgetQueryString()其中前者是不需要变的而后者中可能包含q=这样的页码请求也可能不包含即缺省请求第所以统一用replaceAll()方法将其去掉然后将对应的页码请求串(如q=)加在qs的前面这样做的好处是每个模块都可以使用这个页导航并且不会丢失url中的其他参数(例如今后加入排序功能后url中可能包含dir=desc这样的参数)

在列表jsp(listClientsjsp)中很简单的这样include它(之所以要放在<logic:notEmpty>里是希望在没有记录可显示的时候就不显示页导航了)

<logic:notEmpty name=<%=ClientclassgetName()%>>

<%@include file=/pagerjsp%>

</logic:notEmpty>

经过上面几步的处理我的客户列表已经可以实现分页了效果见下图如果在另外一个模块中也需要分页比如部门列表时只需要修改ListDeptsAction继承AbstractListAction在ListDeptsAction里增加setMaxResults()和setFirstResults()方法在listDeptsjsp中适当的位置include页导航就可以了改动是相当小的

<%@ taglib uri=/WEBINF/strutslogictld prefix=logic %>

<%@ taglib uri=/WEBINF/strutsbeantld prefix=bean %>

<%@ taglib uri=/WEBINF/strutshtmltld prefix=html %>

<%@ page contentType=text/html; charset=gb language=java%>

<html:html locale=true>

<head>

<meta httpequiv=ContentType content=text/html; charset=gb>

</head>

<body>

<table border=>

<tr><th>书名</th><th>作者</th><th>价格</th></tr>

<logic:present name=result>

<logic:iterate id=book name=result type=beanBook >

<logic:present name=book>

<tr>

<td><bean:write name=book property=bookname /></td>

<td> <bean:write name=book property=author /></td>

<td><bean:write name=book property=price /></td>

</tr>

</logic:present>

</logic:iterate>

</logic:present>

</table>

<logic:equal name=page property=hasNextPage value=true>

<html:link page=/pagedo?action=nextPage>nextPage</html:link>

</logic:equal>

<logic:equal name=page property=hasPreviousPage value=true>

<html:link page=/pagedo?action=previousPage>PreviousPage</html:link>

</logic:equal>

共有数据总数<bean:write name=page property=totalRows/>;

共分<bean:write name=page property=totalPages/>页当前是第

<bean:write name=page property=currentPage/>页

</body>

</html:html>

               

上一篇:基于已被证实的Oracle高可用性技术MAA

下一篇:ORACLE入门之物理文件大小的限制