JDBC分页

我想用JDBC来实现分页。 我想知道的实际情况是:“我怎样才能得到第一个50,然后分别从第一页和第二页的数据库获得50条logging”

我的查询是Select * from data [数据表包含20,000行]

对于页面#1我得到50条logging和页面#2我想获得下50个logging。 我怎样才能有效地在JDBC中实现它?

我已经search并发现, rs.absolute(row)是跳过第一页logging的方式,但是在大型结果集上需要一定的时间,我不想承受这个时间。 另外,我不想在查询中使用rownumlimit + offset ,因为这些查询不好用,我不知道为什么,我不想在查询中使用它。

任何人都可以帮助我如何得到有限的ResultSet的分页,或者有什么办法JDBC给我们?

简单地使用JDBC就没有有效的方法。 你必须制定n行限制,从第i项条款开始,直接到SQL是有效的。 根据数据库的不同,这可能会非常简单(请参阅MySQL的LIMIT关键字),但在其他数据库(如Oracle)上,它可能会有点棘手(涉及子查询和使用rownum伪列)。

请参阅此JDBC分页教程: http : //java.avdiel.com/Tutorials/JDBCPaging.html

您应该查询您实际需要显示在当前页面上的数据。 不要将整个数据集拖到Java的内存中,然后在那里进行过滤。 这只会让事情变得不必要的慢一些。

如果你真的很难实现这个和/或为特定的数据库查询SQL查询,那么看看我的答案 。

更新:因为您使用的是Oracle,所以下面是上述答案的一个Oracle针对性的提取:

在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; } 

免责声明: 这篇关于SQL分页和JDBC分页的博文是由我发布的。

无视Hibernate分页,我们可以使用SQL分页/ JDBC分页

SQL分页

有两个基本的方法:

  1. 在零散结果集上运行(每个页面的新查询)
  2. 在完整的结果集上运行

做到这一点的方法是SQL特定的

对于MySQL /许多其他SQL,可以使用限制和偏移来完成

Postgresql: http : //microjet.ath.cx/WebWiki/ResultPaginationWithPostgresql.html

在Oracle中,它使用与处理“Top-N查询”相同的forms,例如谁是最高薪酬的员工,这是最优化的

 select * from ( select a.*, rownum rnum from ( YOUR_QUERY_GOES_HERE -- including the order by ) a where rownum <= MAX_ROWS ) where rnum >= MIN_ROWS 

这里是关于ROW-NUM的一个非常详细的解释

类似的线程

JDBC分页

想到的问题是:当我执行SQL时,如何加载结果? 立即或根据要求? 与此SO线程相同

首先,我们需要了解一些JDBC的基础知识,如Oracle

per javadoc:statement.execute()

 execute: Returns true if the first object that the query returns is a ResultSet object. Use this method if the query could return one or more ResultSet objects. Retrieve the ResultSet objects returned from the query by repeatedly calling Statement.getResutSet. 

我们通过游标访问Resultset中的数据。 注意这个游标与DB的游标不同,它是最初位于第一行数据之前的指针。

数据是根据请求获取的。 而当你执行execute()时,你是第一次获取。

那么,有多less数据被加载? 它是可configuration的。 可以使用ResultSet上的java API setFetchSize()方法来控制驱动程序每次从数据库中提取多less行,它一次检索的块有多大。

例如,假设总结果为1000.如果提取大小为100,则获取第一行将从DB加载100行,并且将从本地存储器加载第二行至第100行。要查询第101行,将另外100行加载到内存中。

从JavaDoc

 Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are needed for ResultSet objects genrated by this Statement. If the value specified is zero, then the hint is ignored. The default value is zero. 

注意“提示”一词 – 它可以被驱动程序的具体实现覆盖。

这也是SQL Server开发人员基于的“限制行数到100”的function。

完成整个解决scheme,要滚动结果,需要考虑API中的ResultSettypes和ScrollableCursor

可以从oracle的这篇文章中find一个示例实现

它来自“Oracle Toplink开发人员指南”中的示例112 JDBC驱动器读取大小

 ReadAllQuery query = new ReadAllQuery(); query.setReferenceClass(Employee.class); query.setSelectionCriteria(new ExpressionBuilder.get("id").greaterThan(100)); // Set the JDBC fetch size query.setFetchSize(50); // Configure the query to return results as a ScrollableCursor query.useScrollableCursor(); // Execute the query ScrollableCursor cursor = (ScrollableCursor) session.executeQuery(query); // Iterate over the results while (cursor.hasNext()) { System.out.println(cursor.next().toString()); } cursor.close(); 

…………………

毕竟,这些问题滔滔不绝

哪个更好的分页方式?

注意SQL应该是ORDER,在SQL方法中是合理的,

否则,可能会在下一页中再次显示一些行。

以下是关于JDBC驱动程序和其他所有答案的Postgresql文档中的一些观点

首先,原始查询需要有一个ORDER BY子句,以便使分页解决scheme合理地工作。 否则,Oracle为第一页,第二页和第N页返回相同的500行是完全有效的

主要区别在于JDBC方式,在取回时需要保持连接。 例如,这可能不适用于无状态的Web应用程序。

对于SQL方式

该语法是SQL特定的,可能不易于维护。 对于JDBC方式

  • 与服务器的连接必须使用V3协议。 这是服务器版本7.4和更高版本的默认设置(并且仅受其支持)。
  • 连接不能处于自动提交模式。 后端在事务结束时closures游标,所以在自动提交模式下,后端将在closures游标之前closures游标。
  • 该语句必须使用ResultSettypes的ResultSet.TYPE_FORWARD_ONLY创build。 这是默认的,所以不需要重写代码来利用这个优点,但是这也意味着你不能向后滚动或者在ResultSet中跳转。
  • 给定的查询必须是单个语句,而不是用分号串在一起的多个语句。

一些进一步阅读

这篇文章是关于光学读取大小的性能调整

如果您使用的是MySQL或PostgreSQL,则限制偏移是您的关键字。 MSSqlServer和Oracle有类似的function,但是我似乎更加痛苦。

对于MySQLPostgreSQL来看看这里:

http://www.petefreitag.com/item/451.cfm

对于Oracle来看看这里:

http://www.oracle-base.com/forums/viewtopic.php?f=2&t=8635

这是链接到一个hibernate解决scheme分页结果: HQL – 分页行标识符

我明白地理解,你不希望JDBC连接有一个巨大的结果集,你保持打开很长时间,并在需要时进行导航。

通常的做法是添加所需的SQL来仅获得完整请求的一个子集,这不幸的是不同于数据库到数据库,并且会使您的SQL语句供应商具体化。 如果我没有记错,LIMIT与MySQL一起使用。 为每个请求询问适当的范围。

我也相信Hibernate包含的function可以让你为HQL做到这一点,但我不熟悉它。

你是否使用某种ORM框架,如hibernate,甚至Java持久性API或只是普通的SQL?

然后我的答案:使用LIMIT和OFFSET http://www.petefreitag.com/item/451.cfm

或者通过ROWNUM运算符,然后你需要一个封装你的SQL,但基本上它是

  select * from (select bla.*, ROWNUM rn from ( <your sql here> ) bla where rownum < 200) where rn >= 150' 

Oracle自8i以来支持标准的ROW_NUMBER()窗口函数,所以你可以使用它。 您可以将其作为参数化查询来完成,因此您只需设置开始和结束行号。 例如

 SELECT * FROM ( SELECT *, ROW_NUMBER() ORDER BY (sort key) AS rowNumber FROM <your table name> ) AS data WHERE rowNumber>=:start AND rowNumber<:end 

(如果你不使用命名参数,请用位置参数placeholder'?'replace:start /:end)

请参阅维基百科上的SELECT SQL,窗口函数 。 本文还列出了支持ROW_NUMBER()标准窗口function的其他数据库。

 PreparedStatement pStmt = // ... however you make it pStmt.setFetchSize( /* desired number of records to get into memory */ ); 

请注意, setFetchSize(int) 只是一个提示 – 我上次用它与MySQL例如,它不被支持。 简要地看一下Oracle文档,看起来他们的JDBC支持它。 我不会在此引用我的意思,但是至less值得一试。 是的,这个答案是脆弱的,但是比实施可靠的解决scheme要less得多。

从本质上讲,你可以发出一切请求,而且你一次只能获取内存的大小(假设你没有保留以前的结果)。 所以你应该把你的抓取大小设置为50,进行连接/查询,显示前50个结果(导致另一个抓取你的查询),等等。

input:

  1. 订单信息示例(A2或D3)(A / D升序/降序)+列
  2. 订单信息示例(A2或D3)(A / D升序/降序)+列
  3. 过滤值
  4. 开始行
  5. 开始行
  6. 最大的行数

结果:

  • 选定的值
  • 所选页面
  • 此sorting中的行的索引
  • 计数可用的数据。 (保存第二个查询)

仅优势查询:

  • 这个filter的可用列的总和
  • 只从db中传输选定的页面
  • 没有dynamicsql正确的顺序

坏处:

  • Oracle Dependend

    (selectc.pk_field,c.numeric_a,c.char_b,c.char_c ROW_NUMBER()over(ORDER BY decode(?,'A1',to_char(c.numeric_a,'FM00000000'),'A2 ('','D1',to_char(c.numeric_a,'FM00000000'),'D2',c.char_b,'D3',c.char_b,'A3',c.char_c,'A' ,c.char_c,'A')desc,c.pk_field asc
    )作为“idx”,COUNT(*)OVER(ORDER BY 1)“cnt”from myTable c where c.haystack =? )x其中x。最大(nvl(?,1),1)和nvl(?,1)-1+之间的“idx”

我知道这个问题是旧的,但这是我如何实现分页,我希望它可以帮助别人

 int pageNo = ....; String query = "SELECT * FROM data LIMIT "; switch (pageNo) { case 0: // no pagination, get all rows query += Integer.MAX_VALUE; // a big value to get all rows break; case 1: // get 1st page ie 50 rows query += 50; break; default: query += String.valueOf((pageNo-1)*50 + 1) ", " + String.valueOf(50); break; } PreparedStatement ps = connection.prepareStatement(query); .... 

使值50为一个名为pageSize的常量,因此可以将其更改为任何数字

以下的java代码运作良好:

 package paginationSample; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; /** * * @ Nwaeze Emmanuel (FUNAI, 2016) */ public class PaginationSample extends javax.swing.JFrame { public void getRows() { Connection con2; Statement stmt2; ResultSet rs2; int j=0; String sz=""; try { // Load MS accces driver class Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); String url = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=" + "C:\\Database2.mdb"; try{ con2 = DriverManager.getConnection(url, "user", ""); System.out.println("Connection Succesfull"); try{ stmt2=con2.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE ); String sql=""; if (txtpage.getText().trim().equals("") || txtpagesize.getText().trim().equals("")){ }else{ int pagesize=Integer.parseInt(txtpagesize.getText()); int page=Integer.parseInt(txtpage.getText()); sql="SELECT * FROM FSRegistration100L WHERE SN >= " + (pagesize*page-pagesize+1) + " AND " + "SN <= " + (pagesize*page); rs2=stmt2.executeQuery(sql); if (rs2.wasNull()){ }else{ while ( rs2.next()){ sz=sz + rs2.getString("RegNo") + "\n"; j++; } txta.setText(sz); txta.append(" Total rows =" + Integer.toString(j)); } } stmt2.close(); con2.close(); } catch (NullPointerException s){ System.err.println("Got an exception166! "); System.out.println(s.getMessage()); } } catch (SQLException e1) { System.err.println("Got an exception1! "); System.err.println(e1.getMessage()); } } catch (ClassNotFoundException e2) { System.err.println("Got an exception2! "); System.err.println(e2.getMessage()); } } private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: getRows(); } // Variables declaration - do not modify private javax.swing.JButton jButton1; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextArea txta; private javax.swing.JTextField txtpage; private javax.swing.JTextField txtpagesize; // End of variables declaration