注:转载于某个网站(不记得了)。
前言
在使用数据库的过程中,不可避免的需要使用到分页的功能,可是JDBC的规范对此却没有很好的解决。对于这个需求很多朋友都有自己的解决方案,比如使用Vector等集合类先保存取出的数据再分页。但这种方法的可用性很差,与JDBC本身的接口完全不同,对不同类型的字段的支持也不好。这里提供了一种与JDBC兼容性非常好的方案。
JDBC和分页
Sun的JDBC规范的制定,有时很让人哭笑不得,在JDBC1.0中,对于一个结果集(ResultSet)你甚至只能执行next()操作,而无法让其向后滚动,这就直接导致在只执行一次SQL查询的情况下无法获得结果集的大小。所以,如果你使用的是JDBC1.0的驱动,那么是几乎无法实现分页的。
好在Sun的JDBC2规范中很好的弥补了这一个不足,增加了结果集的前后滚动操作,虽然仍然不能直接支持分页,但我们已经可以在这个基础上写出自己的可支持分页的ResultSet了。
一个新的Pageable接口及其实现
很显然,看过上面三种实现方法后,我们对新的分页机制有了一个目标,即:不与具体数据库相关;尽可能做到代码重用;尽可能与原JDBC接口的使用方法保持一致;尽可能高的效率。
首先,我们需要提供一个与java.sql.ResultSet向下兼容的接口,把它命名为Pageable,接口定义如下:
public interface Pageable extends java.sql.ResultSet{
/**返回总页数
*/
int getPageCount();
/**返回当前页的记录条数
*/
int getPageRowsCount();
/**返回分页大小
*/
int getPageSize();
/**转到指定页
*/
void gotoPage(int page) ;
/**设置分页大小
*/
void setPageSize(int pageSize);
/**返回总记录行数
*/
int getRowsCount();
/**
* 转到当前页的第一条记录
* @exception java.sql.SQLException 异常说明。
*/
void pageFirst() throws java.sql.SQLException;
/**
* 转到当前页的最后一条记录
* @exception java.sql.SQLException 异常说明。
*/
void pageLast() throws java.sql.SQLException;
/**返回当前页号
*/
int getCurPage();
}
这是一个对java.sql.ResultSet进行了扩展的接口,主要是增加了对分页的支持,如设置分页大小,跳转到某一页,返回总页数等等。
接着,我们需要实现这个接口,由于这个接口继承自ResultSet,并且它的大部分功能也都和ResultSet原有功能相同,所以这里使用了一个简单的Decorator模式。
PageableResultSet2的类声明和成员声明如下:
public class PageableResultSet2 implements Pageable {
protected java.sql.ResultSet rs=null;
protected int rowsCount;
protected int pageSize;
protected int curPage;
protected String command = "";
}
可以看到,在PageableResultSet2中,包含了一个ResultSet的实例(这个实例只是实现了ResultSet接口,事实上它是由各个数据库厂商分别实现的),并且把所有由ResultSet继承来的方法都直接转发给该实例来处理。
PageableResultSet2中继承自ResultSet的主要方法:
//……
public boolean next() throws SQLException {
return rs.next();
}
//……
public String getString(String columnName) throws SQLException {
try {
return rs.getString(columnName);
}
catch (SQLException e) {//这里是为了增加一些出错信息的内容便于调试
throw new SQLException (e.toString()+" columnName="
+columnName+" SQL="+this.getCommand());
}
}
//……
只有在Pageable接口中新增的方法才需要自己的写方法处理。
/**方法注释可参考Pageable.java
*/
public int getCurPage() {
return curPage;
}
public int getPageCount() {
if(rowsCount==0) return 0;
if(pageSize==0) return 1;
//calculate PageCount
double tmpD=(double)rowsCount/pageSize;
int tmpI=(int)tmpD;
if(tmpD>tmpI) tmpI++;
return tmpI;
}
public int getPageRowsCount() {
if(pageSize==0) return rowsCount;
if(getRowsCount()==0) return 0;
if(curPage!=getPageCount()) return pageSize;
return rowsCount-(getPageCount()-1)*pageSize;
}
public int getPageSize() {
return pageSize;
}
public int getRowsCount() {
return rowsCount;
}
public void gotoPage(int page) {
if (rs == null)
return;
if (page < 1)
page = 1;
if (page > getPageCount())
page = getPageCount();
int row = (page - 1) * pageSize + 1;
try {
rs.absolute(row);
curPage = page;
}
catch (java.sql.SQLException e) {
}
}
public void pageFirst() throws java.sql.SQLException {
int row=(curPage-1)*pageSize+1;
rs.absolute(row);
}
public void pageLast() throws java.sql.SQLException {
int row=(curPage-1)*pageSize+getPageRowsCount();
rs.absolute(row);
}
public void setPageSize(int pageSize) {
if(pageSize>=0){
this.pageSize=pageSize;
curPage=1;
}
}
//PageableResultSet2的构造方法:
public PageableResultSet2(java.sql.ResultSet rs) throws java.sql.SQLException {
if(rs==null) throw new SQLException("given ResultSet is NULL","user");
rs.last();
rowsCount=rs.getRow();
rs.beforeFirst();
this.rs=rs;
}
/*如果要提高效率,可以利用select count(*) 语句取得所有记录数,注释掉构造函数的rs.last();rowsCount=rs.getRow();rs.beforeFirst();三句。在调用构造函数后调用此方法获得所有的记录,参数是select count(*)后的结果集
*/
public void setRowsCount(java.sql.ResultSet rs)throws java.sql.SQLException {
if(rs==null) throw new SQLException("given ResultSet is NULL","user");
rowCount=rs.getInt(1);
}
这里只是简单的取得一个总记录数,并将记录游标移回初始位置(before first),同时将参数中的ResultSet赋给成员变量。
这里只是简单的取得一个总记录数,并将记录游标移回初始位置(before first),同时将参数中的ResultSet赋给成员变量。
Pageable的使用方法
因为Pageable接口继承自ResultSet,所以在使用方法上与ResultSet一致,尤其是在不需要分页功能的时候,可以直接当成ResultSet使用。而在需要分页时,只需要简单的setPageSize, gotoPage,即可。
PreparedStatement pstmt=null;
Pageable rs=null;
……//构造SQL,并准备一个pstmt.
rs=new PageableResultSet2(pstmt.executeQuery());//构造一个Pageable
rs.setPageSize(20);//每页20个记录
rs.gotoPage(2);//跳转到第2页
for(int i=0; i<rs.getPageRowsCount(); i++){//循环处理
int id=rs.getInt(“ID”);
……//继续处理
rs.next();
}
总结
一个好的基础类应该是便于使用,并且具备足够的可移植性,同时要保证其功能的完善。在上面的实现中,我们从java.sql.ResultSet接口继承出Pageable,并实现了它。这就保证了在使用中与JDBC原有操作的一致性,同时对原有功能没有缩减。
同时它也是易于使用的,因为封装了一切必要的操作,所以在你的代码中唯一显得"难看"和"不舒服"的地方就是需要自己去构造一个PageableResultSet2。不过只要你愿意,这也是可以解决的。
当然它也有具有充分的可移植性,当你将数据库由Oracle变为Mysql或者SQLServer的时候,你仍然可以使用这些分页的代码。它在使用中(或者说在移植的过程中)唯一的限制就是你必须要使用一个支持JDBC2的驱动(现在明白为什么我把类命名为PageableResultSet2了吧。:P),不过,好在JDBC2已经成为标准了,绝大多数的数据库(如Oracle, Mysql, SQLServer)都有自己的或者第三方提供的JDBC2的驱动。
OK,这个分页的实现是否对你的编程有帮助呢?仔细看看,其实真正自己写的代码并不多的,大部分都只是简单的转发操作。一个合适的模式应用可以帮你很大忙。
分享到:
相关推荐
java链接sqlserver数据库包如下错误时: java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver at java.net.URLClassLoader.findClass(Unknown Source) ...添加sqljdbc4-2.0包即可
《SQL Server 数据库连接驱动:sqljdbc4-4.0.jar 深度解析》 在信息化社会中,数据库管理系统的角色至关重要,SQL Server作为微软公司推出的强大关系型数据库管理系统,广泛应用于各种业务场景。而要与SQL Server...
在描述中提到,“JAVA支持SQL SERVICE 2000版本的JDBC”,这指的是该驱动是Java语言开发的,它实现了Java Database Connectivity (JDBC) API,使得Java开发者能够通过标准的JDBC接口来访问和管理SQL Server 2000...
dm8-oracle-jdbc16-wrapper.jar
在Java编程环境中,连接Microsoft SQL Server数据库通常需要特定的驱动程序,这就是所谓的JDBC驱动程序。`sqljdbc4-4.0.jar`是Microsoft提供的一个适用于Java的SQL Server JDBC驱动程序,它允许Java应用程序通过JDBC...
sqljdbc4-chs-4.0.2206.100.jar sqljdbc4-chs-4.0.2206.100.jar sqljdbc4-chs-4.0.2206.100.jar sqljdbc4 com.microsoft.sqlserver sqlserver
首先,我们来理解一下"sqljdbc4-4.0.jar"的含义。"sqljdbc"代表这是针对SQL Server的JDBC驱动,而"4.0"则表示该驱动的版本号,它符合JDBC 4.0规范,提供了对Java SE 6的支持。这个版本的驱动引入了多项新特性和性能...
含两个文件hive-jdbc-3.1.2-standalone.jar和apache-hive-3.1.2-bin.tar.gz 含两个文件hive-jdbc-3.1.2-standalone.jar和apache-hive-3.1.2-bin.tar.gz 含两个文件hive-jdbc-3.1.2-standalone.jar和apache-hive-...
x-pack-sql-jdbc-6.4.0到x-pack-sql-jdbc-7.6.0各个版本jdbc驱动下载
sqljdbc4-4.0.jar下载 《无需积分》,自行提取 Maven安装cmd指令 mvn install:install-file -DgroupId=com.microsoft.sqlserver -DartifactId=sqljdbc4 -Dversion=4.0 -Dpackaging=jar -Dfile=G:\迅雷下载\BB-sql...
通过JDBC,Java程序员可以编写代码来执行SQL语句,处理查询结果,以及管理数据库连接。JDBC驱动程序是连接Java应用程序与数据库的关键组件,它们实现了JDBC API,提供了具体的数据库访问功能。 **二、sqljdbc4-4.0....
这两个文件`clickhouse-jdbc-0.2.4.jar`和`clickhouse-jdbc-0.2.4-jar-with-dependencies.jar`都是Clickhouse-JDBC驱动的不同版本。 `clickhouse-jdbc-0.2.4.jar`是基础的JAR文件,它包含了Clickhouse-JDBC驱动的...
taos-jdbcdriver-2.0.39-dist.jar
Java 第三阶段增强分析需求,代码实现能力【JDBC】---- 代码 Java 第三阶段增强分析需求,代码实现能力【JDBC】---- 代码 Java 第三阶段增强分析需求,代码实现能力【JDBC】---- 代码 Java 第三阶段增强分析需求,...
hive-jdbc-3.1.2-standalone适用于linux
本文将详细讲解如何使用“sqljdbc4-3.0.zip”这个驱动包来实现MS SQL Server的连接。 `sqljdbc4-3.0.jar`是Microsoft为Java开发人员提供的一个JDBC驱动程序,它允许Java应用程序通过JDBC API与SQL Server进行通信。...
hive-jdbc-2.1.0-standalone.jar
赠送jar包:sqlite-jdbc-3.15.1.jar; 赠送原API文档:sqlite-jdbc-3.15.1-javadoc.jar; 赠送源代码:sqlite-jdbc-3.15.1-sources.jar; 赠送Maven依赖信息文件:sqlite-jdbc-3.15.1.pom; 包含翻译后的API文档:...
TDengine驱动Jar包(2.0.34)
完成上述配置后,Java程序便可以使用`java.sql.DriverManager`类来建立与SQL Server的连接,例如: ```java Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); Connection conn = DriverManager.get...