传统的想法都是返回一个Set, List, Iterator之类。
这些方法实际上都要把数据从ResultSet读出来,缓存起来,即使用户也许本来只是想把这些数据用一定的格式输送到客户端而已。如果用户直接使用ResultSet,本来是可以省掉这个缓存的。
当然,也有把ResultSet直接adapt成Iterator的。但是这样一来,ResultSet和Connection的生命期就成了问题。就象jaghuang说的,什么时候rs.close()呢?
我提一个alternative,大家看看合适不合适。
与其返回一个Collection, array,不如接受一个回调函数。这样,用户可以自己决定是否缓存,如何缓存。而且,用户也不需要关心close和jdbc。
具体如下:
定义接口:
interface Row{
int getInt(String s);
int getInt(int i);
Object getObject(String s);
Object getObject(int i);
...
//所有ResultSet里面的getter。
}
这相当于一个只读的隐藏了jdbc细节的ResultSet的对应版本。用户的回调接受一个Row当作参数。
再定义回调接口:
interface RowListner{
//返回true表示继续下一行,false表示不要了。
boolean receive(Row row);
}
底层数据引擎:
void getData(RowListern l){
...
final ResultSet rs = ...;
try{
while(rs.next()){
if(!l.receive(Result2Row.adapt(rs)))
break;
}
finally{rs.close();}
...
}
Result2Row是一个把ResultSet转换到Row格式的adapter。遇到SqlException, 它把它变成一个RuntimeException或者某一个子类。具体我就不写了。
这样做的好处是,当用户不需要缓存数据的时候,节省空间。另外,即使用户需要缓存数据,他也有选择使用ArrayList, LinkedList, Hashtable等任意一种collection的自由。框架没必要去帮助用户做这个决定。
用它实现返回Vector或者Iterator不过是举手之劳:
class VectorRowListener implements RowListener{
public boolean receive(Row r){
v.add(r.getString(1));
return true;
}
private final Vector v = new Vector();
Vector getResult{return v;}
}
VectorRowListener vr = new VectorRowListener();
x.getData(vr);
Vector v = vr.getResult();
同理,我也可以不把结果缓存在数组中。比如说,我可以定制一个固定长度的数组,超过这个长度,就不再继续读了:
class ArrayRowListener implements RowListener{
public boolean receive(Row r){
arr[i++]=r.getString(1);
return i==arr.length;
}
private final String[] arr;
private int i = 0;
int getCount(){return i;}
ArrayRowListener(String[] a){this.arr=a;}
}
String[] arr = new String[200];//最多读200个
ArrayRowListener ar = new ArrayRowListener(arr);
x.getData(ar);
int recordRead = ar.getCount();
这应该可以帮助实现分页查询的功能吧?(当底层数据库不支持top语法时)