menu

开发进行时...

crazy coder

Avatar

JoSQL - 用SQL来查询Java对象

一个大集合里面过滤获取其中的部分数据是一个很常见的需求,比如在财务系统中,用户会维护汇率这样的数据:

public class ExchangeRate {
    private String fromCurrency;
    private String toCurrency;
    private Date fromDate;
    private Date thruDate;
    private double rate;
}

在系统计算的时候,会用到类似这样的方法,来获取某个时间点2个货币单位之间的汇率:

public double getRate(String fromCurrency, String toCurrency, Date when)

最常见的实现方法就是用查询语句(SQL/HSQL/EJBQL)来获取,考虑到这种类型数据的2个特性:
1. 数据量比较少
2. 经常被查询到
我们往往会给它们加上Cache来提高性能,在Hibernate里面我们可以配置查询缓存来实现,考虑到Hibernate查询缓存是用查询参数做为Cache Key的特性,为了节省缓存空间,更常见的做法是缓存所有ExchangeRate,然后从这个集合里面过滤,比如说用apache的Collection Utils来实现:

return CollectionUtils.find(getAllExchangeRates(), new Predicate() {
    public boolean evaluate(Object o) {
        ExchangeRate r = (ExchangeRate) o;
        return r.getFromCurrency().equals(fromCurrency) && r.getToCurrency().equals(toCurrency) && ...
    }
}).getRate();

我们需要一个Java匿名内部类来做,这样的代码看起来不是很简洁,而且和大家熟悉的SQL是不同的风格,如果可以用一种和它们类似的方式来实现,会好很多,JoSQL ( http://josql.sourceforge.net/ ) 就是这样的工具:

JoSQL (SQL for Java Objects) provides the ability for a developer to apply a SQL statement to a collection of Java Objects. JoSQL provides the ability to search, order and group ANY Java objects and should be applied when you want to perform SQL-like queries on a collection of Java Objects.

用JoSQL来实现上面的例子:

Query q = new Query();
q.parse("select * from ExchangeRate where fromCurrency = :fromCurrency and toCurrency = :toCurrency and fromDate <= :when and thruDate >= :when");
q.setVariable("fromCurrency", fromCurrency);
q.setVariable("toCurrency", toCurrency);
q.setVariable("when", date);
return q.execute(getAllExchangeRates()).getResults().get(0).getRate();

我们可以看到和SQL的查询方式非常类似,这里只是一个JoSQl最简单的功能,在它的文档里面:http://josql.sourceforge.net/manual/examples.html还可以看到Order, Grouping, Execute On等特性,对于实现常见的用户需求来说是非常有用的。

回到上面的例子,默认的JoSQL代码对于实现这种fiter性质的功能来说还是稍显麻烦,我们可以包装一下:

JoSQLUtil.find(list, "fromCurrency = ? and toCurrency = ? and fromDate <= ? and thruDate >= ?", new Object[]{fromCurrency, toCurrency, date, date}).get(0).getRate();

JoSQLUtil里面可以处理掉一些默认的拼凑SQL,设置参数等代码,这样会变得更加简洁了。


这个还挺好玩的

跟 LINQ 学的?

评论已关闭