其它常见的方法还有每次翻页都查询一次数据库,从ResultSet中只取出一页数据(使用rs.last();rs.getRow()获得总计录条数,使用rs.absolute()定位到本页起始记录)。这种方式在某些数据库(如oracle)的JDBC实现中差不多也是需要遍历所有记录,实验证明在记录数很大时速度非常慢。
至于缓存结果集ResultSet的方法则完全是一种错误的做法。因为ResultSet在Statement或Connection关闭时也会被关闭,如果要使ResultSet有效势必长时间占用数据库连接。
因此比较好的分页做法应该是每次翻页的时候只从数据库里检索页面大小的块区的数据。这样虽然每次翻页都需要查询数据库,但查询出的记录数很少,网络传输数据量不大,如果使用连接池更可以略过最耗时的建立数据库连接过程。而在数据库端有各种成熟的优化技术用于提高查询速度,比在应用服务器层做缓存有效多了。
在oracle数据库中查询结果的行号使用伪列ROWNUM表示(从1开始)。例如select * from employee where rownum<10 返回前10条记录。但因为rownum是在查询之后排序之前赋值的,所以查询employee按birthday排序的第100到120条记录应该这么写:
select * from (
select my_table.*, rownum as my_rownum from (
select name, birthday from employee order by birthday
) my_table where rownum <120
) where my_rownum>=100
mySQL可以使用LIMIT子句:
select name, birthday from employee order by birthday LIMIT 99,20
DB2有rownumber()函数用于获取当前行数。
SQL Server没研究过,可以参考这篇文章:
http://www.csdn.net/develop/article/18/18627.shtm
在Web程序中分页会被频繁使用,但分页的实现细节却是编程过程中比较麻烦的事情。大多分页显示的查询操作都同时需要处理复杂的多重查询条件,sql语句需要动态拼接组成,再加上分页需要的记录定位、总记录条数查询以及查询结果的遍历、封装和显示,程序会变得很复杂并且难以理解。因此需要一些工具类简化分页代码,使程序员专注于业务逻辑部分。下面是我设计的两个工具类:
PagedStatement
封装了数据库连接、总记录数查询、分页查询、结果数据封装和关闭数据库连接等操作,并使用了PreparedStatement支持动态设置参数。
RowSetPage
参考PetStore的page by page iterator模式, 设计RowSetPage用于封装查询结果(使用OracleCachedRowSet缓存查询出的一页数据,关于使用CachedRowSet封装数据库查询结果请参考
JSP页面查询显示常用模式
)以及当前页码、总记录条数、当前记录数等信息, 并且可以生成简单的HTML分页代码。
PagedStatement 查询的结果封装成RowsetPage。
下面是简单的
使用示例
:
-
//DAO查询数据部分代码:
- …
-
public
RowSetPage getEmployee(
String
gender,
int
pageNo)
throws
Exception
{ -
String
sql=
“select emp_id, emp_code, user_name, real_name from employee where gender =?”
; -
//使用Oracle数据库的分页查询实现,每页显示5条
-
PagedStatement pst =
new
PagedStatementOracleImpl(sql, pageNo, 5); - pst.setString(1, gender);
-
return
pst.executeQuery(); - }
-
//Servlet处理查询请求部分代码:
- …
-
int
pageNo; -
try
{ -
//可以通过参数pageno获得用户选择的页码
-
pageNo =
Integer
.parseInt(request.getParameter(
“pageno”
) ); -
}
catch
(
Exception
ex){ -
//默认为第一页
- pageNo=1;
- }
-
String
gender = request.getParameter(
“gender”
); -
request.setAttribute(
“empPage”
, myBean.getEmployee(gender, pageNo) ); - …
-
//JSP显示部分代码
-
<%@ page
import
=
“page.RowSetPage”
%> - …
-
<script language=
“javascript”
> - function doQuery(){
-
form1.actionType.value=
“doQuery”
; - form1.submit();
- }
- </script>
- …
- <form name=form1 method=get>
- <input type=hidden name=actionType>
- 性别:
-
<input type=text name=gender size=1 value=
“<%=request.getParameter(”
gender
“)%>”
> -
<input type=button value=
” 查询 ”
οnclick=
“doQuery()”
> - <%
-
RowSetPage empPage = (RowSetPage)request.getAttribute(
“empPage”
); -
if
(empPage ==
null
) empPage = RowSetPage.EMPTY_PAGE; - %>
- …
-
<table cellspacing=
“0”
width=
“90%”
> - <tr> <td>ID</td> <td>代码</td> <td>用户名</td> <td>姓名</td> </tr>
- <%
-
javax.sql.
RowSet
empRS = (javax.sql.
RowSet
) empPage.getRowSet(); -
if
(empRS!=
null
)
while
(empRS.next() ) { - %>
- <tr>
-
<td><%= empRS.getString(
“EMP_ID”
)%></td> -
<td><%= empRS.getString(
“EMP_CODE”
)%></td> -
<td><%= empRS.getString(
“USER_NAME”
)%></td> -
<td><%= empRS.getString(
“REAL_NAME”
)%></td> - </tr>
- <%
-
}
// end while
- %>
- <tr>
- <%
-
//显示总页数和当前页数(pageno)以及分页代码。
-
//此处doQuery为页面上提交查询动作的javascript函数名, pageno为标识当前页码的参数名
- %>
-
<td colspan=4><%= empPage .getHTML(
“doQuery”
,
“pageno”
)%></td> - </tr>
- </table>
- </form>
效果如图:
因为分页显示一般都会伴有查询条件和查询动作,页面应已经有校验查询条件和提交查询的javascript方法(如上面的doQuery),所以RowSetPage.getHTML()生成的分页代码在用户选择新页码时直接回调前面的处理提交查询的javascript方法。注意在显示查询结果的时候上次的查询条件也需要保持,如<input type=text name=gender size=1 value=”<%=request.getParameter(“gender”)%>”>。同时由于页码的参数名可以指定,因此也支持在同一页面中有多个分页区。
另一种分页代码实现是生成每一页的URL,将查询参数和页码作为QueryString附在URL后面。这种方法的缺陷是在查询条件比较复杂时难以处理,并且需要指定处理查询动作的servlet,可能不适合某些定制的查询操作。
如果对RowSetPage.getHTML()生成的默认分页代码不满意可以编写自己的分页处理代码,RowSetPage提供了很多getter方法用于获取相关信息(如当前页码、总页数、 总记录数和当前记录数等)。
在实际应用中可以将分页查询和显示做成jsp taglib, 进一步简化JSP代码,屏蔽Java Code。
附:分页工具类的源代码, 有注释,应该很容易理解。
1.Page.java
2.RowSetPage.java(RowSetPage继承Page)
3.PagedStatement.java
4.PagedStatementOracleImpl.java(PagedStatementOracleImpl继承PagedStatement)
您可以任意使用这些源代码,但必须保留author evan_zhao@hotmail.com字样
-
///
-
//
-
// Page.java
-
// author: evan_zhao@hotmail.com
-
//
-
///
-
package
page; -
import
java.util.
List
; -
import
java.util.
ArrayList
; -
import
java.util.
Collection
; -
import
java.util.
Collections
; -
/**
-
* Title: 分页对象<br>
-
* Description: 用于包含数据及分页信息的对象<br>
-
* Page类实现了用于显示分页信息的基本方法,但未指定所含数据的类型,
-
* 可根据需要实现以特定方式组织数据的子类,<br>
-
* 如RowSetPage以RowSet封装数据,ListPage以List封装数据<br>
-
* Copyright: Copyright (c) 2002 <br>
-
* @author evan_zhao@hotmail.com <br>
-
* @version 1.0
-
*/
-
public
class
Page
implements
java.io.
Serializable
{ -
public
static
final
Page EMPTY_PAGE =
new
Page(); -
public
static
final
int
DEFAULT_PAGE_SIZE = 20; -
public
static
final
int
MAX_PAGE_SIZE = 9999; -
private
int
myPageSize = DEFAULT_PAGE_SIZE; -
private
int
start; -
private
int
avaCount,totalSize; -
private
Object
data; -
private
int
currentPageno; -
private
int
totalPageCount; -
/**
-
* 默认构造方法,只构造空页
-
*/
-
protected
Page(){ -
this
.init(0,0,0,DEFAULT_PAGE_SIZE,
new
Object
()); - }
-
/**
-
* 分页数据初始方法,由子类调用
-
* @param start 本页数据在数据库中的起始位置
-
* @param avaCount 本页包含的数据条数
-
* @param totalSize 数据库中总记录条数
-
* @param pageSize 本页容量
-
* @param data 本页包含的数据
-
*/
-
protected
void
init(
int
start,
int
avaCount,
int
totalSize,
int
pageSize,
Object
data){ -
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) { -
//throw new RuntimeException(“记录条数大于总条数?!”);
- }
-
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(“Start Index to Page No: ” + start + “-” + currentPageno);
- }
-
public
Object
getData(){ -
return
this
.data; - }
-
/**
-
* 取本页数据容量(本页能包含的记录数)
-
* @return 本页能包含的记录数
-
*/
-
public
int
getPageSize(){ -
return
this
.myPageSize; - }
-
/**
-
* 是否有下一页
-
* @return 是否有下一页
-
*/
-
public
boolean
hasNextPage() { -
/*
-
if (avaCount==0 && totalSize==0){
-
return false;
-
}
-
return (start + avaCount -1) < totalSize;
-
*/
-
return
(
this
.getCurrentPageNo()<
this
.getTotalPageCount()); - }
-
/**
-
* 是否有上一页
-
* @return 是否有上一页
-
*/
-
public
boolean
hasPreviousPage() { -
/*
-
return start > 1;
-
*/
-
return
(
this
.getCurrentPageNo()>1); - }
-
/**
-
* 获取当前页第一条数据在数据库中的位置
-
* @return
-
*/
-
public
int
getStart(){ -
return
start; - }
-
/**
-
* 获取当前页最后一条数据在数据库中的位置
-
* @return
-
*/
-
public
int
getEnd(){ -
int
end =
this
.getStart() +
this
.getSize() -1; -
if
(end<0) { - end = 0;
- }
-
return
end; - }
-
/**
-
* 获取上一页第一条数据在数据库中的位置
-
* @return 记录对应的rownum
-
*/
-
public
int
getStartOfPreviousPage() { -
return
Math
.max(start-myPageSize, 1); - }
-
/**
-
* 获取下一页第一条数据在数据库中的位置
-
* @return 记录对应的rownum
-
*/
-
public
int
getStartOfNextPage() { -
return
start + avaCount; - }
-
/**
-
* 获取任一页第一条数据在数据库中的位置,每页条数使用默认值
-
* @param pageNo 页号
-
* @return 记录对应的rownum
-
*/
-
public
static
int
getStartOfAnyPage(
int
pageNo){ -
return
getStartOfAnyPage(pageNo, DEFAULT_PAGE_SIZE); - }
-
/**
-
* 获取任一页第一条数据在数据库中的位置
-
* @param pageNo 页号
-
* @param pageSize 每页包含的记录数
-
* @return 记录对应的rownum
-
*/
-
public
static
int
getStartOfAnyPage(
int
pageNo,
int
pageSize){ -
int
startIndex = (pageNo-1) * pageSize + 1; -
if
( startIndex < 1) startIndex = 1; -
//System.out.println(“Page No to Start Index: ” + pageNo + “-” + startIndex);
-
return
startIndex; - }
-
/**
-
* 取本页包含的记录数
-
* @return 本页包含的记录数
-
*/
-
public
int
getSize() { -
return
avaCount; - }
-
/**
-
* 取数据库中包含的总记录数
-
* @return 数据库中包含的总记录数
-
*/
-
public
int
getTotalSize() { -
return
this
.totalSize; - }
-
/**
-
* 取当前页码
-
* @return 当前页码
-
*/
-
public
int
getCurrentPageNo(){ -
return
this
.currentPageno; - }
-
/**
-
* 取总页码
-
* @return 总页码
-
*/
-
public
int
getTotalPageCount(){ -
return
this
.totalPageCount; - }
-
/**
-
*
-
* @param queryJSFunctionName 实现分页的JS脚本名字,页码变动时会自动回调该方法
-
* @param pageNoParamName 页码参数名称
-
* @return
-
*/
-
public
String
getHTML(
String
queryJSFunctionName,
String
pageNoParamName){ -
if
(getTotalPageCount()<1){ -
return
“<input type=’hidden’ name='”
+pageNoParamName+
“‘ value=’1’ >”
; - }
-
if
(queryJSFunctionName ==
null
|| queryJSFunctionName.trim().
length
()<1) { -
queryJSFunctionName =
“gotoPage”
; - }
-
if
(pageNoParamName ==
null
|| pageNoParamName.trim().
length
()<1){ -
pageNoParamName =
“pageno”
; - }
-
String
gotoPage =
“_”
+queryJSFunctionName; -
StringBuffer
html =
new
StringBuffer
(
“/n”
); -
html.append(
“<script language=/”Javascript1.2/”>/n”
) -
.append(
“function ”
).append(gotoPage).append(
“(pageNo){ /n”
) -
.append(
” var curPage=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(
” return true; /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(
” return false; /n”
) -
// .append( ” } /n”)
-
.append(
” } /n”
) -
.append(
“}”
) -
.append(
“</script> /n”
) -
.append(
“”
); -
html.append(
“<table border=0 cellspacing=0 cellpadding=0 align=center width=80%> /n”
) -
.append(
” <tr> /n”
) -
.append(
” <td align=left><br> /n”
); -
html.append(
” 共”
).append( getTotalPageCount() ).append(
“页”
) -
.append(
” [”
) .append(getStart()).append(
“..”
).append(getEnd()) -
.append(
“/”
).append(
this
.getTotalSize()).append(
“] /n”
) -
.append(
” </td> /n”
) -
.append(
” <td align=right> /n”
); -
if
(hasPreviousPage()){ -
html.append(
“[<a href=’javascript:”
).append(gotoPage) -
.append(
“(”
) .append(getCurrentPageNo()-1) -
.append(
“)’>上一页</a>] /n”
); - }
-
html.append(
” 第”
) -
.append(
” <select name='”
) -
.append(pageNoParamName).append(
“‘ onChange=’javascript:”
) -
.append(gotoPage).append(
“(this.value)’>/n”
); -
String
selected =
“selected”
; -
for
(
int
i=1;i<=getTotalPageCount();i++){ -
if
( i == getCurrentPageNo() ) -
selected =
“selected”
; -
else
selected =
“”
; -
html.append(
” <option value='”
).append(i).append(
“‘ ”
) -
.append(selected).append(
“>”
).append(i).append(
“</option> /n”
); - }
-
if
(getCurrentPageNo()>getTotalPageCount()){ -
html.append(
” <option value='”
).append(getCurrentPageNo()) -
.append(
“‘ selected>”
).append(getCurrentPageNo()) -
.append(
“</option> /n”
); - }
-
html.append(
” </select>页 /n”
); -
if
(hasNextPage()){ -
html.append(
” [<a href=’javascript:”
).append(gotoPage) -
.append(
“(”
).append((getCurrentPageNo()+1)) -
.append(
“)’>下一页</a>] /n”
); - }
-
html.append(
“</td></tr></table> /n”
); -
return
html.toString(); - }
- }
-
///
-
//
-
// RowSetPage.java
-
// author: evan_zhao@hotmail.com
-
//
-
///
-
package
page; -
import
javax.sql.
RowSet
; -
/**
-
* <p>Title: RowSetPage</p>
-
* <p>Description: 使用RowSet封装数据的分页对象</p>
-
* <p>Copyright: Copyright (c) 2003</p>
-
* @author evan_zhao@hotmail.com
-
* @version 1.0
-
*/
-
public
class
RowSetPage
extends
Page { -
private
javax.sql.
RowSet
rs; -
/**
-
*空页
-
*/
-
public
static
final
RowSetPage EMPTY_PAGE =
new
RowSetPage(); -
/**
-
*默认构造方法,创建空页
-
*/
-
public
RowSetPage(){ -
this
(
null
, 0,0); - }
-
/**
-
*构造分页对象
-
*@param crs 包含一页数据的OracleCachedRowSet
-
*@param start 该页数据在数据库中的起始位置
-
*@param totalSize 数据库中包含的记录总数
-
*/
-
public
RowSetPage(
RowSet
crs,
int
start,
int
totalSize) { -
this
(crs,start,totalSize,Page.DEFAULT_PAGE_SIZE); - }
-
/**
-
*构造分页对象
-
*@param crs 包含一页数据的OracleCachedRowSet
-
*@param start 该页数据在数据库中的起始位置
-
*@param totalSize 数据库中包含的记录总数
-
*@pageSize 本页能容纳的记录数
-
*/
-
public
RowSetPage(
RowSet
crs,
int
start,
int
totalSize,
int
pageSize) { -
try
{ -
int
avaCount=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.
SQLException
sqle){ -
throw
new
RuntimeException
(sqle.toString()); - }
- }
-
/**
-
*取分页对象中的记录数据
-
*/
-
public
javax.sql.
RowSet
getRowSet(){ -
return
rs; - }
- }
-
///
-
//
-
// PagedStatement.java
-
// author: evan_zhao@hotmail.com
-
//
-
///
-
package
page; -
import
foo.DBUtil; -
import
java.math.
BigDecimal
; -
import
java.util.
List
; -
import
java.util.
Iterator
; -
import
java.util.
Collections
; -
import
java.sql.
Connection
; -
import
java.sql.
SQLException
; -
import
java.sql.
ResultSet
; -
import
java.sql.
Statement
; -
import
java.sql.
PreparedStatement
; -
import
java.sql.
Timestamp
; -
import
javax.sql.
RowSet
; -
/**
-
* <p>Title: 分页查询</p>
-
* <p>Description: 根据查询语句和页码查询出当页数据</p>
-
* <p>Copyright: Copyright (c) 2002</p>
-
* @author evan_zhao@hotmail.com
-
* @version 1.0
-
*/
-
public
abstract
class
PagedStatement { -
public
final
static
int
MAX_PAGE_SIZE = Page.MAX_PAGE_SIZE; -
protected
String
countSQL, querySQL; -
protected
int
pageNo,pageSize,startIndex,totalCount; -
protected
javax.sql.
RowSet
rowSet; -
protected
RowSetPage rowSetPage; -
private
List
boundParams; -
/**
-
* 构造一查询出所有数据的PageStatement
-
* @param sql query sql
-
*/
-
public
PagedStatement(
String
sql){ -
this
(sql,1,MAX_PAGE_SIZE); - }
-
/**
-
* 构造一查询出当页数据的PageStatement
-
* @param sql query sql
-
* @param pageNo 页码
-
*/
-
public
PagedStatement(
String
sql,
int
pageNo){ -
this
(sql, pageNo, Page.DEFAULT_PAGE_SIZE); - }
-
/**
-
* 构造一查询出当页数据的PageStatement,并指定每页显示记录条数
-
* @param sql query sql
-
* @param pageNo 页码
-
* @param pageSize 每页容量
-
*/
-
public
PagedStatement(
String
sql,
int
pageNo,
int
pageSize){ -
this
.pageNo = pageNo; -
this
.pageSize = pageSize; -
this
.startIndex = Page.getStartOfAnyPage(pageNo, pageSize); -
this
.boundParams =
Collections
.synchronizedList(
new
java.util.
LinkedList
()); -
this
.countSQL =
“select count(*) from ( ”
+ sql +
“) ”
; -
this
.querySQL = intiQuerySQL(sql,
this
.startIndex, pageSize); - }
-
/**
-
*生成查询一页数据的sql语句
-
*@param sql 原查询语句
-
*@startIndex 开始记录位置
-
*@size 需要获取的记录数
-
*/
-
protected
abstract
String
intiQuerySQL(
String
sql,
int
startIndex,
int
size); -
/**
-
*使用给出的对象设置指定参数的值
-
*@param index 第一个参数为1,第二个为2,。。。
-
*@param obj 包含参数值的对象
-
*/
-
public
void
setObject(
int
index,
Object
obj)
throws
SQLException
{ -
BoundParam bp =
new
BoundParam(index, obj); - boundParams.remove(bp);
- boundParams.add( bp);
- }
-
/**
-
*使用给出的对象设置指定参数的值
-
*@param index 第一个参数为1,第二个为2,。。。
-
*@param obj 包含参数值的对象
-
*@param targetSqlType 参数的数据库类型
-
*/
-
public
void
setObject(
int
index,
Object
obj,
int
targetSqlType)
throws
SQLException
{ -
BoundParam bp =
new
BoundParam(index, obj, targetSqlType); - boundParams.remove(bp);
- boundParams.add(bp );
- }
-
/**
-
*使用给出的对象设置指定参数的值
-
*@param index 第一个参数为1,第二个为2,。。。
-
*@param obj 包含参数值的对象
-
*@param targetSqlType 参数的数据库类型(常量定义在java.sql.Types中)
-
*@param scale 精度,小数点后的位数
-
* (只对targetSqlType是Types.NUMBER或Types.DECIMAL有效,其它类型则忽略)
-
*/
-
public
void
setObject(
int
index,
Object
obj,
int
targetSqlType,
int
scale)
throws
SQLException
{ -
BoundParam bp =
new
BoundParam(index, obj, targetSqlType, scale) ; - boundParams.remove(bp);
- boundParams.add(bp);
- }
-
/**
-
*使用给出的字符串设置指定参数的值
-
*@param index 第一个参数为1,第二个为2,。。。
-
*@param str 包含参数值的字符串
-
*/
-
public
void
setString(
int
index,
String
str)
throws
SQLException
{ -
BoundParam bp =
new
BoundParam(index, str) ; - boundParams.remove(bp);
- boundParams.add(bp);
- }
-
/**
-
*使用给出的字符串设置指定参数的值
-
*@param index 第一个参数为1,第二个为2,。。。
-
*@param timestamp 包含参数值的时间戳
-
*/
-
public
void
setTimestamp(
int
index,
Timestamp
timestamp)
throws
SQLException
{ -
BoundParam bp =
new
BoundParam(index, timestamp) ; - boundParams.remove(bp);
- boundParams.add( bp );
- }
-
/**
-
*使用给出的整数设置指定参数的值
-
*@param index 第一个参数为1,第二个为2,。。。
-
*@param value 包含参数值的整数
-
*/
-
public
void
setInt(
int
index,
int
value)
throws
SQLException
{ -
BoundParam bp =
new
BoundParam(index,
new
Integer
(value)) ; - boundParams.remove(bp);
- boundParams.add( bp );
- }
-
/**
-
*使用给出的长整数设置指定参数的值
-
*@param index 第一个参数为1,第二个为2,。。。
-
*@param value 包含参数值的长整数
-
*/
-
public
void
setLong(
int
index,
long
value)
throws
SQLException
{ -
BoundParam bp =
new
BoundParam(index,
new
Long
(value)) ; - boundParams.remove(bp);
- boundParams.add( bp );
- }
-
/**
-
*使用给出的双精度浮点数设置指定参数的值
-
*@param index 第一个参数为1,第二个为2,。。。
-
*@param value 包含参数值的双精度浮点数
-
*/
-
public
void
setDouble(
int
index,
double
value)
throws
SQLException
{ -
BoundParam bp =
new
BoundParam(index,
new
Double
(value)) ; - boundParams.remove(bp);
- boundParams.add( bp);
- }
-
/**
-
*使用给出的BigDecimal设置指定参数的值
-
*@param index 第一个参数为1,第二个为2,。。。
-
*@param bd 包含参数值的BigDecimal
-
*/
-
public
void
setBigDecimal(
int
index,
BigDecimal
bd)
throws
SQLException
{ -
BoundParam bp =
new
BoundParam(index, bd ) ; - boundParams.remove(bp);
- boundParams.add( bp);
- }
-
private
void
setParams(
PreparedStatement
pst)
throws
SQLException
{ -
if
(pst==
null
||
this
.boundParams==
null
||
this
.boundParams.size()==0 )
return
; - BoundParam param;
-
for
(
Iterator
itr =
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);
- }
- }
- }
-
/**
-
* 执行查询取得一页数据,执行结束后关闭数据库连接
-
* @return RowSetPage
-
* @throws SQLException
-
*/
-
public
RowSetPage executeQuery()
throws
SQLException
{ -
System
.out.println(
“executeQueryUsingPreparedStatement”
); -
Connection
conn = DBUtil.getConnection(); -
PreparedStatement
pst =
null
; -
ResultSet
rs =
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 )
return
RowSetPage.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 =
new
RowSetPage(
this
.rowSet,startIndex,totalCount,pageSize); -
return
this
.rowSetPage; -
}
catch
(
SQLException
sqle){ -
//System.out.println(“executeQuery SQLException”);
- sqle.printStackTrace();
-
throw
sqle; -
}
catch
(
Exception
e){ - e.printStackTrace();
-
throw
new
RuntimeException
(e.toString()); -
}
finally
{ -
//System.out.println(“executeQuery finally”);
- DBUtil.close(rs, pst, conn);
- }
- }
-
/**
-
*将ResultSet数据填充进CachedRowSet
-
*/
-
protected
abstract
RowSet
populate(
ResultSet
rs)
throws
SQLException
; -
/**
-
*取封装成RowSet查询结果
-
*@return RowSet
-
*/
-
public
javax.sql.
RowSet
getRowSet(){ -
return
this
.rowSet; - }
-
/**
-
*取封装成RowSetPage的查询结果
-
*@return RowSetPage
-
*/
-
public
RowSetPage getRowSetPage() { -
return
this
.rowSetPage; - }
-
/**
-
*关闭数据库连接
-
*/
-
public
void
close(){ -
//因为数据库连接在查询结束或发生异常时即关闭,此处不做任何事情
-
//留待扩充。
- }
-
private
class
BoundParam { -
int
index; -
Object
value; -
int
sqlType; -
int
scale; -
public
BoundParam(
int
index,
Object
value) { -
this
(index, value, java.sql.
Types
.OTHER); - }
-
public
BoundParam(
int
index,
Object
value,
int
sqlType) { -
this
(index, value, sqlType, 0); - }
-
public
BoundParam(
int
index,
Object
value,
int
sqlType,
int
scale) { -
this
.index = index; -
this
.value = value; -
this
.sqlType = sqlType; -
this
.scale = scale; - }
-
public
boolean
equals(
Object
obj){ -
if
(obj!=
null
&&
this
.getClass().isInstance(obj)){ - BoundParam bp = (BoundParam)obj;
-
if
(
this
.index==bp.index)
return
true
; - }
-
return
false
; - }
- }
- }
-
///
-
//
-
// PagedStatementOracleImpl.java
-
// author: evan_zhao@hotmail.com
-
//
-
///
-
package
page; -
import
java.sql.
ResultSet
; -
import
java.sql.
SQLException
; -
import
javax.sql.
RowSet
; -
import
oracle.jdbc.rowset.OracleCachedRowSet; -
/**
-
* <p>Title: 分页查询Oracle数据库实现</p>
-
* <p>Copyright: Copyright (c) 2002</p>
-
* @author evan_zhao@hotmail.com
-
* @version 1.0
-
*/
-
public
class
PagedStatementOracleImpl
extends
PagedStatement { -
/**
-
* 构造一查询出所有数据的PageStatement
-
* @param sql query sql
-
*/
-
public
PagedStatementOracleImpl(
String
sql){ -
super
(sql); - }
-
/**
-
* 构造一查询出当页数据的PageStatement
-
* @param sql query sql
-
* @param pageNo 页码
-
*/
-
public
PagedStatementOracleImpl(
String
sql,
int
pageNo){ -
super
(sql, pageNo); - }
-
/**
-
* 构造一查询出当页数据的PageStatement,并指定每页显示记录条数
-
* @param sql query sql
-
* @param pageNo 页码
-
* @param pageSize 每页容量
-
*/
-
public
PagedStatementOracleImpl(
String
sql,
int
pageNo,
int
pageSize){ -
super
(sql, pageNo, pageSize); - }
-
/**
-
*生成查询一页数据的sql语句
-
*@param sql 原查询语句
-
*@startIndex 开始记录位置
-
*@size 需要获取的记录数
-
*/
-
protected
String
intiQuerySQL(
String
sql,
int
startIndex,
int
size){ -
StringBuffer
querySQL =
new
StringBuffer
(); -
if
(size !=
super
.MAX_PAGE_SIZE) { -
querySQL.append(
“select * from (select my_table.*,rownum as my_rownum from(”
) - .append( sql)
-
.append(
“) my_table where rownum<”
).append(startIndex + size) -
.append(
“) where my_rownum>=”
).append(startIndex); -
}
else
{ -
querySQL.append(
“select * from (select my_table.*,rownum as my_rownum from(”
) - .append(sql)
-
.append(
“) my_table ”
) -
.append(
“) where my_rownum>=”
).append(startIndex); - }
-
return
querySQL.toString(); - }
-
/**
-
*将ResultSet数据填充进CachedRowSet
-
*/
-
protected
RowSet
populate(
ResultSet
rs)
throws
SQLException
{ -
OracleCachedRowSet ocrs =
new
OracleCachedRowSet(); - ocrs.populate(rs);
-
return
ocrs; - }
- }