用OO方法解一道算术题

05-12-26 banq
本篇主要为说明使用面向对象的分析和设计方法可以帮助更快地认识事物,更快地排除编程设计过程一个个拦路虎。

用OO方法解一道算术题:

http://www.jdon.com/artichect/oo_math.htm

         

1
cats_tiger
2005-12-27 10:53
我认为将startIndex作为key的组成部分是没有必要的,因为如果startIndex最终会作为sql的一部分:select * from a limit...,而且,如果使用MS SqlServer,startIndex就不起作用了。Hibernate就是把sql、参数、分页信息等等作为缓存key,所以Hibernate的批量查询缓存的实用性并不高。缓存中的数据块应该从第一条记录开始,到MaxResults,如果分页超过了这个范围,则调整MaxResults并重新执行查询。还有,分页的时候不要从数据库中取,而是在缓存中的数据块中进行分页,下面是我的key的实现:

public class CachedQueryKey implements Serializable {

private String queryString;

private Object[] args;

//....getters/setters,hasCode,equals,toString

}

数据块采用List作为数据内容也是不合理的,因为根据查询内容的不同会产生许多VO,还不如使用RowSet,我实现了一个动态Bean:

public interface Rows extends Serializable{

/**

* 将ResultSet对象的一行导入。

*/

public void addRow(final ResultSet rs) throws SQLException;

/**

* 将Row对象导入

*/

public void addRow(final Row row);

/**

* 遍历ResultSet对象,并全部导入

*/

public void addRows(final ResultSet rs) throws SQLException;

/**

* 遍历行集的所有行,返回Iterator接口。实现者可以采用内部类实现Iterator接口。

*/

public Iterator iterator();

/**

* 返回指定行

*/

public Row get(int index);

/**

* 如果行集中没有数据,返回true

*/

public boolean isEmpty();

/**

* 返回行集的最大预设容量(number of row)

*/

public int getMaxRows();

/**

* 预设行集的容量(number of row)

*/

public void setMaxRows(int maxRows);

/**

* 返回行集的实际容量

*/

public int getRows();

/**

* 取得行集中某一行的指定列。

* @param colName 列名

* @param rowIndex 行索引,第一行为0,第二行为1,...

*/

public Object get(String colName, int rowIndex);

/**

* 返回指定范围的子行集。

* @param startIndex 起始索引,必须>=0 <=getRows

* @param maxRows 子集的容量

*/

public Rows sub(int startIndex, int maxRows);

/**

* 将行集的每一行转换为指定类型的java bean对象,并以List的形式返回。

* @param type 指定的类型,必须是标准的JavaBean

*/

public List toList(Class type);

}

这个是接口,实现类必须注意不能使用Map作为每一行,因为Keys会占用过多的内存,如果追求效率,可以使用数组Object[][]

由于很多应用要求实时性较高,所以缓存的使用也是可选的,我使用动态代理实现,这样,如果不想使用缓存就不要代理即可。

还有,分页算法应该和查询以及缓存的应用分开,作为一个单独的Aspact使用,分页算法最重要的是取得真实查询结果的总行数,这个数据是分页的基础,它也需要缓存。

banq
2005-12-27 11:38
切磋一下:

>数据块采用List作为数据内容也是不合理的,因为根据查询内容的不同会产生许多VO,还不如使用RowSet,我实现了一个动态Bean

数据块中存放的是主键集合,不是VO;不能使用属于持久层的对象在全层之间传来传去,你的自己动态Bean不错。

这里List和Block都是一个临时变量,在Jdon框架中,在全层之间传递是PageIterator,类似你的Rows

>我认为将startIndex作为key的组成部分是没有必要的

真正到数据块查询(dataBaseBlock)的startIndex不是查询条件的startIndex,而是经过计算:

int blockID = start / count;

int blockStart = blockID * count;

中的blockStart,

这样能够保证从数据库或缓存获取数据块时,表明这个数据块是符合我们起点要求的数据块。

如果不使用起点作为Key一部分,那么可能缓存不起作用,因为同一个查询条件下,多个页面的区别就是起点不一样,这样我们可以将包涵每个页面的数据块缓存。

另外,“缓存中的数据块应该从第一条记录开始”不知你是指符合查询条件的第一条吗?还是当前页面的第一条呢?我前面是指当前页面第一条。

你可能也是这个意思,你说"分页超过了这个范围,则调整MaxResults并重新执行查询",

这是一种实现思路,只是我现在提供遍历的这个类PageIterator是一个简单的POJO,是一个DTO,没有自己操作数据块能力,这也给我带来实现难度。

所以有时想,MF提出的非贫血模型多好,自己不但带数据,还可以在任何时刻操作数据库,但是它是不是象Hibernate的Open in View模式,将持久层的潘多拉盒子打开,在各层到处是飞舞的数据库影子。

banq
2005-12-27 11:44
可喜的是有cats_tiger 这样同志者和我一样在做这样的探索,而我在google上搜索看到更多是在数据库端做功夫,这里有一篇文章试图通过存储过程等数据库操作实现批量查询的案例:

海量数据库的查询优化及分页算法方案:

http://www.pconline.com.cn/pcedu/empolder/db/sql/0501/538958_6.html

但是在设计上这是一个错误的方向,向数据库要性能要潜力的余地已经很小了。

更重要的是,造成代码可维护性和可拓展性很差,更可怕的是:几乎所有搞数据库系统的人都是这种思路,思维不改;而且他们对选择其他道路还在怀疑观望,这种思维下的程序代码质量能高吗?

真应该让更多人明白:数据库时代已经过去了。

yuxie
2005-12-27 22:08
老大,既然这是一个错误的方向,那么拿这篇文章举的一个相关例子,在一个有上亿条记录的人口数据库里边,不做数据库优化的情况下,如何能够按某个条件(比如人名或出生日期),做到快速查出相关记录呢?这里的纪录一般可是关系到多个表的哦。

我最近刚做了一个sql的优化(实际上是hsql),优化前查询速度是80多秒,优化后查询速度是80多毫秒,请问老大为什么说向数据库要性能要潜力的余地已经很小了呢?

请用缓存实现上边说的人口数据库的例子~这里的查询都是随机的,一次查出来的数据一般也都在一页之内。一页以上大家就在加条件限制范围了,没人会一页一页翻着看哦。

猜你喜欢
2Go 1 2 下一页