【原创】JAVA实现关系数据库的翻页 by masse@CSDN: 这个方法没有什么特别的,其实也算不上原创。也是在学习中得出来的。因此如果侵犯了别人的权益,请来信通知。为了方便初学者了解原理,代码中我没有使用任何框架。代码可以适用于mysql,oracle,sqlserver,db2等等主流关系数据库。
以下代码是我从自己以前写的程序中抽取出来的核心,只能表述思路,如要使用,可能还需要很多调整。(1) 数据库表sys_User定义如下:
ID Name Email Desc …
1 masse [email protected] 当午 …
其中,ID为整型,其它均为字符串。(2) User类,请自行为每个方法添加getter和setter方法。为了方便,我写了User(ResultSet)这个构造函数。
public class User
{
public User(ResultSet rs)
{
id = rs.getInt("ID");
name = rs.getString("Name");
email = rs.getString("Email");
desc = rs.getString("Desc");
}
private int id;
private String name;
private String email;
private String desc;
}(3) sysUserTable类,用于数据库读取,我这里仅仅给出了最核心部分。其中对于start,count等的有效性参数,请自行判断;sql语句如果有查询的filter,或者order等语句,也可根据情况自行调整。我只给出程序框架。// 取出从start开始的count条记录。如,start为1,count为20,则取出数据库前20条记录
public class SysUserTable
{
public List getUsers(Connection conn, int start, int count) throws
Exception
{
PreparedStatement pStmt = null;
ResultSet rs = null;
List result = new ArrayList();
try
{
String sql = "SELECT * FROM sys_User";
pStmt = conn.preparedStatement(sql);
rs = pStmt.executeQuery();
if (rs.absolute(startRow))
{
result.add(new User(rs));
for (int rowIndex = 0; rowIndex < rowCount - 1; rowIndex++)
{
if (!rs.next())
{
break;
}
result.add(new User(rs));
}
}
}
catch (Exception e)
{
throw e; // process exception here
}
finally
{
// close rs & pStmt here
}
return result;
}
}(4) JSP页面的实现。基本的思路就是,根据当前页数,计算出需要的start即可。如指定每页count条,当前在第n页,那么start=(n-1)*count+1。然后作为参数,即可得到翻页结果集。具体的实现可以用传统的翻页,也可用ajax。这里灵活性很大,就不再赘述了。
以下代码是我从自己以前写的程序中抽取出来的核心,只能表述思路,如要使用,可能还需要很多调整。(1) 数据库表sys_User定义如下:
ID Name Email Desc …
1 masse [email protected] 当午 …
其中,ID为整型,其它均为字符串。(2) User类,请自行为每个方法添加getter和setter方法。为了方便,我写了User(ResultSet)这个构造函数。
public class User
{
public User(ResultSet rs)
{
id = rs.getInt("ID");
name = rs.getString("Name");
email = rs.getString("Email");
desc = rs.getString("Desc");
}
private int id;
private String name;
private String email;
private String desc;
}(3) sysUserTable类,用于数据库读取,我这里仅仅给出了最核心部分。其中对于start,count等的有效性参数,请自行判断;sql语句如果有查询的filter,或者order等语句,也可根据情况自行调整。我只给出程序框架。// 取出从start开始的count条记录。如,start为1,count为20,则取出数据库前20条记录
public class SysUserTable
{
public List getUsers(Connection conn, int start, int count) throws
Exception
{
PreparedStatement pStmt = null;
ResultSet rs = null;
List result = new ArrayList();
try
{
String sql = "SELECT * FROM sys_User";
pStmt = conn.preparedStatement(sql);
rs = pStmt.executeQuery();
if (rs.absolute(startRow))
{
result.add(new User(rs));
for (int rowIndex = 0; rowIndex < rowCount - 1; rowIndex++)
{
if (!rs.next())
{
break;
}
result.add(new User(rs));
}
}
}
catch (Exception e)
{
throw e; // process exception here
}
finally
{
// close rs & pStmt here
}
return result;
}
}(4) JSP页面的实现。基本的思路就是,根据当前页数,计算出需要的start即可。如指定每页count条,当前在第n页,那么start=(n-1)*count+1。然后作为参数,即可得到翻页结果集。具体的实现可以用传统的翻页,也可用ajax。这里灵活性很大,就不再赘述了。
但是觉得优势有以下
(1)没有使用任何框架,适合初学者,也适合对某些成型系统进行升级修改。同时扩展性很强。
(2)使用几乎所有的关系数据库,因为没有使用任何特殊的sql语法。比如top ,limit,rownum等等,sql也可以根据情况修改,实现任何查询的翻页。
(3)性能:具体性能没有经过测试,以前在一个复杂的应用下,测过50万的数据,还不错。如果应用简单,这个性能指数会有所上升。
感觉分2种一种逻辑上实现分页 一种数据上实现分页
2种加起来才算一个分页
感觉你的逻辑和数据混合了你的table类写成接口感觉比较好
public interface SysUserTable
{
public List getUsers(Connection conn, int start, int count) throws
Exception;
}
你的table类写成接口感觉比较好 愚见了 哈哈
而且代码是写了另外的代码来自动生成的,
相当于是自己实现的一套框架(那个框架最初是一个同事写的,很牛的人)。最后封装的形式如下public interface Service
{
public int getUserCount()throws Exception;
public int getUserCount(String filter)throws Exception;
public List getUsers()throws Exception;
public List getUsers(String filter)throws Exception;
public List getUsers(int start ,int count)throws Exception;
public List getUsers(String filter,int start ,int count)throws Exception;
public List getUsers(String filter,int start ,int count,String[] sortNames,int[] sortTypes)throws Exception;
}仅一个单独的实体表相关的接口就有几十个。
因为是用自己写的框架生成的,所以也不存在工作量的问题。
也不会把连接暴露出来。
在security方面,可以再加入接口调用的登陆认证。如果要针对数据库优化,只需要改动生成代码的框架,改里面的代码模板,
改几行,就能实现代码的重构。。我给出的仅仅是通用数据库无框架实现翻页的雏形罢了
看我上面帖子里面,不使用,top ,limit,rownum同时我在具体项目的实现里面是做了数据库区分优化的,会根据不同的数据库进行不同的优化策略调整。
多次调用getUsers(Connection conn, int start, int count)时,它不是多次查询了吗?
如果这中间表里的数据发生变化了呢??岂不是两次的rs都不一样?
比如我写一个通用的/**
* filter:查询串,sortNames排序字段,sortTypes排序类型,1为升序,0为降序
* start为开始记录,count为返回记录数
*/
public List getUsers(Connection conn, String filter,String[] sortNames,int[] sortTypes,int start, int count) throws
Exception
{
String sql = "SELECT * FROM sys_User";
if(filter!=null)
{
sql += " " + filter;
}
if(sortNames!=null && sortNames.length>0)
{
sql += " ORDER BY";
for(int i=0;i<sortNames.length;i++)
{
sql += " " + sortNames[i] + (sortTypes[i]==1?" ASC":" DESC");
if(i<sortNames.length-1) sql +=",";
}
}
// 下面的同我上面的代码
}这样就能实现分页+查询+排序了。
此时,原来的方法,就可以写成
public List getUsers(Connection conn, int start, int count) throws
Exception
{
return getUsers(conn,null,null,null,start,count);
}当然,这个为了实现通用,代价就是效率问题。上面已经提到。
但是这个非常简单,
即便以后数据库换成xml,也可用xml-jdbc进行转换,
不必要关心数据库类型。
sqlserver有人说用top,但是用top的效率很低,尤其是在要排序的情况下分页。mysql用limit
oracle用rownum都在底层用接口,根据数据库类型得到不同的sql语句,
如果是未知关系数据库,就缺省用通用的。鱼和熊掌不可兼得。有时候为了效率,的确要麻烦点。但通常自己做个东西玩,没有多少数据量,为了移植方便,最好通用。
有时候甚至直接用xml就代替了数据库。
{
sql += " WHERE " + filter;
}
定义一个xml文件
<table intf='User' name='sys_User' version="1.0" >
<column name="id" type="int" primary-key="true"/>
<column name="username" type="string" length="20"/>
<column name="password" type="string"/>
</table>然后根据数据库类型参数(mysql/oracle/sqlserver)
自动生成对应的sql语句(用以初始化数据库)
自动生成User类
自动生成User的底层接口和apache-db下的一个项目很类似。
可以参考他的官方网。
用Hibernate吧,感觉如果要作成通用的话,工程很大。
楼主的封装方法和Hibernate的行封装方法很象。^-^
谢谢你的答疑. 学了不少.虽说可能会降低效率,不过你的解决方法是我见过最简单简洁的了(非框架)!
直接定义简单的xml文件(1)生成通用数据库初始化sql脚本,数据库说明文档
(2)生成底层类和接口(能够处理外键、关联等复杂逻辑,并且根据数据库类型进行特定优化)
(3)生成界面元素和布局(div+css,支持autocomplete,级联select等常见ajax特性,支持日期选择框等常见控件)
(4)支持数据库脚本的版本,能够自动生成数据库升级脚本(如从1.0到2.0改动了数据库,可以取出任意两个版本之间的差异升级脚本),数据库升级的说明文档单个的功能都已经在平时的工作中做过,尽管效果没有理想的好。
最近一直太忙,这个工作量也非常大,实在抽不出时间总结。呵呵。
{
public String getPagedSqlString(String sql,int start,int end);
}public class DefaultManager implements DBManager
{
public String getPagedSqlString(String sql,int start,int end)
{ // 这里就是第一篇文章中的sql语句,不再重复
}
}public class OracleManager implements DBManager
{
public String getPagedSqlString(String sql,int start,int end)
{
// sql + " WHERE ROWNUM<="+end+" AND ROWNUM>="+start;
}
}public class MysqlManager implements DBManager
{
public String getPagedSqlString(String sql,int start,int end)
{
// sql + " LIMIT "+start+","+end;
}
}public class SybaseManager implements DBManager
{
public String getPagedSqlString(String sql,int start,int end)
{
// use rowcount;
}
}public class MssqlManager implements DBManager
{
public String getPagedSqlString(String sql,int start,int end)
{
// use top;
}
}public class Db2Manager implements DBManager
{
public String getPagedSqlString(String sql,int start,int end)
{
// use fetch first n row only;
}
}如果没有找到对应的数据库类型,就用default的。