PETSTORE分页的疑惑,请板桥指教!

roadbai 02-10-27

看了一下PETSTORE的分页和各位以前的讨论,对PETSTORE的分页程序有个疑问。在PETSTROE中是用返回PAGE类来分页的,每次只返回一页的数据,但是好像每次调用下一页的时候应该执行类似以下的GET方法,这样岂不是每次都去查询一次数据库(rs = ps.executeQuery();),我觉得应该有把第一次查询结果缓存的做法,还是我的理解有问题?请板桥指教!

public Page getProducts(String categoryID, int start,
int count, Locale l)
throws CatalogDAOSysException {

Connection c = null;
PreparedStatement ps = null;
ResultSet rs = null;
Page ret = null;

try {
c = getDataSource().getConnection();

ps = c.prepareStatement("select a.productid, name, descn "
+ "from (product a join "
+ "product_details b on "
+ "a.productid=b.productid) "
+ "where locale = ? "
+ "and a.catid = ? "
+ "order by name",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ps.setString(1, l.toString());
ps.setString(2, categoryID);
rs = ps.executeQuery();
if (start >= 0 && rs.absolute(start+1)) {
boolean hasNext = false;
List items = new ArrayList();
do {
items.add(new Product(rs.getString(1).trim(),
rs.getString(2).trim(),
rs.getString(3).trim()));
} while ((hasNext = rs.next()) && (--count > 0));
ret = new Page(items, start, hasNext);
}
else {
ret = Page.EMPTY_PAGE;
}

rs.close();
ps.close();

c.close();
return ret;
}
catch (SQLException se) {
throw new CatalogDAOSysException("SQLException: "
+ se.getMessage());
}
}

fuck
2002-10-27 21:09

确实如此,这就是分页的两难问题.
缺点:每次只显示一页中的10条也要取所有的即使是100万条记录.
优点:每次取是都是当前数据库的即时记录,如果缓存下来,而数据库又有新的记录你就看不到了.

所以你如果想实时就要全部取出来,如果不想实时可以用ChechRowSet,这样就不要每次从数据库中取了.当然用MYSQL就不用担心了,因为LIMIT可以只取每几到第几条.

其实你也不必过份担心性能问题,因为JDBC的ResultSet实现原理是这样:
不允许序列化:即结果集不能自己被writeObject().它依赖于Connection,
Connection一断,ResultSet就立即清为null.这样ResultSet中并没有保存实际的数据对象,只是保存了二维指针.第一维是记录号,每二位是该记录号的column指针.数据库中数据不管多大,ResultSet本身并不大.只有当你next()到一条记录,然后调用getXXX(col)时才去通过Connection再从数据库中把数据取出来给你.所以即使有一百万条记录,也不过是一万个指点针(JAVA的句柄而已),并没有多大的资源浪费.

cc
2002-10-28 10:13

fuck说得跟banq说得有些出入,如果resultSet真是这样先进的话,那就更用不到把resultset放到Collection里面了,也就更谈不到自己去做Iterator了。

fuck
2002-10-28 11:33

你要注意,ResultSet规定是不能序列化的,也就是它是一个即时的数据结构,依赖于Connection,Connection断了它也就空了,你不能总把Connection占着吧?那只好把ResultSet的值取出来先封装到别的结构中,把Connection断开让给别人啊.

fuck
2002-10-28 11:47

其实你可以看一下ORACLE,MSSQLSERVER,MYSQL等JDBC中ResultSet中是如何实现的.如果ResultSet能保存实际数据,假设先用一条记录(多条记录就开数组或Collection)那么它就应该这样
package org.gjt.mm.mysql;
public class ResultSet implements java.sql.ResultSet
{
HashTable a = new ........
public ResultSet()
{
在构造方法中通过Connection取得数据封装起来
byte[] data1 = Connection.readBytes(column1);
byte[] data2 = Connection.readBytes(column2);
//这只是说明,不一定真的有readBytes()方法,但肯定是先取得数据的原始字节,网络和内存中的任何数据都是无符合序列,JAVA的byte
然后把data1,data2,datan转化为相应的类型.
a.put(column1,data1);
.......................
a.put(columnn,datan);


}
在getXXX()时应该这样
public getString(column1);
{
return a.get(column);
}
}
这样做它是可以保存实际数据的,

但是真实的ResultSet是不允许这样实现的,它的getXXX()
先保存一个全局counter,next()到几,然后
getString(column)
{
byte[] date = Connection.readBytes(counter,column);
}
是在getXXX的时候才去从数据库中取的.
如果不封到别的结构中,Connection就要永远占着,这是不可能的.

2Go 1 2 下一页