结果集转换为分页

21

如何在JSP中将Resultset对象转换为分页视图?

例如,这是我的查询和结果集:

pst = con.prepareStatement("select userName, job, place from contact");
rs = pst.executeQuery();
5个回答

41

首先,您需要向JSP添加一或两个额外的请求参数:firstrow和(可选)rowcountrowcount也可以省略并在服务器端完全定义。

然后,在JSP中添加一堆分页按钮: next按钮应指示Servletfirstrow的值增加rowcount的值。 previous按钮显然应将firstrow的值减去rowcount的值。不要忘记正确处理负值和溢出! 您可以借助于SELECT count(id)进行操作。

然后触发特定的SQL查询以检索结果的子列表。但是确切的SQL语法取决于所使用的DB。 在MySQL和PostgreSQL中,可以使用LIMITOFFSET子句轻松实现:

private static final String SQL_SUBLIST = "SELECT id, username, job, place FROM"
    + " contact ORDER BY id LIMIT %d OFFSET %d";

public List<Contact> list(int firstrow, int rowcount) {
    String sql = String.format(SQL_SUBLIST, firstrow, rowcount);

    // Implement JDBC.
    return contacts;
}

在 Oracle 中,你需要使用带有 rownum 子句的子查询,它应该看起来像这样:

private static final String SQL_SUBLIST = "SELECT id, username, job, place FROM"
    + " (SELECT id, username, job, place FROM contact ORDER BY id)"
    + " WHERE ROWNUM BETWEEN %d AND %d";

public List<Contact> list(int firstrow, int rowcount) {
    String sql = String.format(SQL_SUBLIST, firstrow, firstrow + rowcount);

    // Implement JDBC.
    return contacts;
}

在DB2中,您需要使用OLAP函数row_number()来实现此功能:

private static final String SQL_SUBLIST = "SELECT id, username, job, place FROM"
    + " (SELECT row_number() OVER (ORDER BY id) AS row, id, username, job, place"
    + " FROM contact) AS temp WHERE row BETWEEN %d AND %d";

public List<Contact> list(int firstrow, int rowcount) {
    String sql = String.format(SQL_SUBLIST, firstrow, firstrow + rowcount);

    // Implement JDBC.
    return contacts;
}

我不熟悉MSSQL,但它在语法上与DB2相似。另请参见此主题

最后,使用JSTL c:forEach 以通常的方式在 JSP 页面中呈现子列表。

<table>
    <c:forEach items="${contacts}" var="contact">
        <tr>
            <td>${contact.username}</td>
            <td>${contact.job}</td>
            <td>${contact.place}</td>
        </tr>
    </c:forEach>
</table>
<form action="yourservlet" method="post">
    <input type="hidden" name="firstrow" value="${firstrow}">
    <input type="hidden" name="rowcount" value="${rowcount}">
    <input type="submit" name="page" value="next">
    <input type="submit" name="page" value="previous">
</form>

注意有些人可能会建议你需要选择整个表并将List<Contact>保存在会话范围中,并利用List#subList()进行分页。但是这对于具有数千行和多个并发用户的表来说远非内存高效。

对于那些在JSF / MySQL上下文中使用h:dataTable组件感兴趣的人,你可能会发现这篇文章很有用。它还包含了一些有用的与语言无关的数学知识,可以使"类似谷歌"的分页很好地运作。


假设当用户查看某个页面时,数据库插入和删除操作正在进行。随着时间的推移,行号将不稳定,这会导致用户位置发生意外变化。 - djna
这不是一个问题。你不想查看已经删除的项目或错过编辑后的数据。唯一的解决办法是将整个数据库表拉入Java的内存中,并仅在其中工作,但你不想这样做。 - BalusC
@BalusC - 哇,太棒了。这个答案我自己也可以好好利用。 - ChadNC
BalusC,这是一个很好的汇编,但Oracle SQL是错误的。我在我的答案中写了正确的SQL。 - Vasily Komarov
你的Oracle查询不起作用。如果下限大于1,则无法在ROWNUM中使用BETWEEN,因为每行将在分配给它的ROWNUM值之前被过滤。因此,“where ROWNUM BETWEEN 2 and xxx”始终返回一个空结果集。请参见https://dev59.com/v2Yr5IYBdhLWcg3wXJAK#13740166。 - KeatsPeeks

4

这个 Oracle 示例是错误的。

没错,在外部查询中我们有良好的 ROWNUM 值,但它仍然是伪列,因此我们不能在其上使用 BETWEEN。我们需要再加一层查询。

正确的 SQL 代码如下:

SELECT c.*
  FROM (SELECT c.*, ROWNUM as rnum
          FROM (SELECT id, username, job, place FROM contact ORDER BY id) c) c
 WHERE c.rnum BETWEEN 5 AND 10

同志们,使用固定的SQL字符串和Statement类是缓慢的。每次执行SQL时,Oracle都需要解析它。
//Slooow example
Satement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select * from my_table where id = 11");

使用PreparedStatement和绑定参数。

   //Faster example
   PreparedStatement ps = conn.getPrepareStatement("select * from my_table where id = ?");
   ps.setInt(1, 11);

最快的解决方案是将您的SQL放入Oracle存储过程中,并使用CallableStatement来调用它。

//Fastest example
CallableStatement cs = conn.prepareCall("{? = call my_plsql_function(?)}");
cs.setInt(1, 11);

2
以下是您可以做的几件事情:
- 将结果集转换为对象/记录列表。 - 根据所需页面大小,计算基于结果集的页面数。 - 根据要在页面上显示的项目数量,检查请求参数以获取所需页面和偏移量。例如,如果您要在第4页上显示12个项目,则偏移量为48。 - 基于项目数量确定总页面数。 - 根据您确定的偏移量显示项目(仅从第48个项目开始显示)。 - 根据您确定的总页面数生成分页。
这是您的基本方法。您可以通过以下方式进行调整:
- 确定一种将查询限制为页面的方法(但这不能帮助您确定页面大小)。 - 使用高级的分页方法。 - 等等。

如果结果集有数千行,则这不是非常高效的。最好在数据库层面进行分页。 - BalusC

0

你可以使用displaytag来进行分页或结果集,但是你需要从displaytag下载一些jar文件。

首先,你需要创建一个servlet:StudentList.java。

public class StudentList extends HttpServlet 

{ public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        ArrayList al=new ArrayList();
        StudentDao stdo=new StudentDao(); // this is DAO Class (Data Acccess Object)

        try
        {
            al=stdo.getStudentList(); //getstudent list dao method
        }
        catch (SQLException e) 
        {
            e.printStackTrace();
        }
        catch (Exception e) 
        {
            e.printStackTrace();
        }
        request.setAttribute("al",al);

        RequestDispatcher rd=request.getRequestDispatcher("StudentPaging.jsp");
        rd.forward(request,response);

}

}

// 数据访问对象方法

public ArrayList getStudentList() throws SQLException,Exception
{
    ArrayList ai=new ArrayList();
    Connection con=null;
    Statement st=null;
    ResultSet rs=null;
    Date dt=new Date();
    SimpleDateFormat sdf=new SimpleDateFormat("dd/MM/yyyy");
    StudentInformation sdata=null;

    con=MyConnection.creatConnection();
    if(con!=null)
    {
        st=con.createStatement();
        String select="select * from STUDENT";
        System.out.println(select);

        rs=st.executeQuery(select);
        if(rs!=null)
        {
            while(rs.next())
            {
                sdata=new StudentInformation();
                sdata.setSid(rs.getString("SID"));
                sdata.setFirstName(rs.getString("FIRSTNAME"));
                sdata.setMiddleName(rs.getString("MIDDLENAME"));
                sdata.setLastName(rs.getString("LASTNAME"));
                dt=rs.getDate("SDATE");
                sdata.setDateofbirth(sdf.format(dt));
                sdata.setGender(rs.getString("GENDER"));
                sdata.setAddress(rs.getString("ADDRESS"));
                sdata.setHigestQulification(rs.getString("HIQULIFICATION"));
                sdata.setLanguageKnow(rs.getString("LANGUAGE"));
                sdata.setHobby(rs.getString("HOBBY"));
                sdata.setTermCondition(rs.getString("TERMCON"));
                ai.add(sdata);
            }
        }
    }
    return ai;
}

enter image description here


-1

查找“值列表模式”,并应用它。这通常是处理这些问题的最佳方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接