Java - 在代码中避免长SQL查询

时间:2011-07-25 11:06:36

标签: java sql coding-style

在我的Java代码中,我有类似的东西:

ResultSet rs = statement.executeQuery(
                   "SELECT a,b,c FROM foo -- here starts the long query"+
                   " -- that is not yet finished " +
                   " -- that still has something to say... "+ 
                   " -- now the end !"
               );

我想像这样清理我的代码:

ResultSet rs = statement.executeQuery(all_queries.getQuery("The very long one"));

我已经读过ResourceBundle用于本地化。所以我不认为它与我的情况相符。

all_queries应该是什么?

编辑: 对我来说最重要的是清理代码。

8 个答案:

答案 0 :(得分:11)

我会把它放在一个带有sql扩展名的文件中并实现Queries,如:

Queries {
    static public String getQuery(String name) {
        return loadResource("/com/example/queries/" + name + ".sql");
    }
}

用户:

conn.prepareStatement(Queries.getQuery("my_query"));

当然,这只是一种方法。您可以使Queries返回Statement,或者甚至使用动态代理将其掩盖在简单的Java接口(其中代理处理程序可以创建语句,设置参数和运行查询)之后。您的里程可能会有所不同。

增加了好处:sql文件具有语法着色,并且方式比Java中的字符串更容易维护。

答案 1 :(得分:3)

数据结构视角

因为您需要从键(名称)到值(长查询)的映射,这是使用dictionary (aka map, associative array)数据结构实现的。

使您的配置远离代码

您应该将配置存储在与代码分开的文件中。我推荐.ini配置格式,它非常易读,可以分为几个部分,几乎可以用于任何计算机语言。

您的配置文件如下所示:

[users_queries]    
find_max_user_id = SELECT max(id) 
                   FROM users 
                   WHERE ...
name             = query
...
...

使用ini4j模块,获取查询就像以下一样简单:

Ini.Section section = ini.get("users_queries");
String query = section.get("find_max_user_id");

答案 2 :(得分:2)

我会让他们

 static final String someMeaningfulName = " ... ";

外部化到资源包之类的文本文件会起作用,但我不相信它是必要的,甚至不是一个好主意,因为它可能导致一种认为这些不是真正的“代码”和因此,变化并不需要进行测试。

答案 3 :(得分:1)

一个简单的解决方案是使用普通属性文件,答案来自Cleanest way to build an SQL string in Java

唯一的问题是新行需要用“\”分隔 e.g。

CURRENT_DATE=select sysdate \
from dual

然后你可以使用

Queries.getQuery("CURRENT_DATE");

是的,“\”仍然很丑,但与使用Java的String / StringBuilder连接相比,它更清晰,更容易格式化,imo。


如果您想支持更清晰的格式,也许您可​​以创建自己的解析器或使用XML格式。但我觉得这太过分了。


偏离主题:得爱Groovy的多行字符串(无耻):

public static final String MY_QUERY = """\
  select col1, col2
  from table1
  where col1=:param1
""";

答案 4 :(得分:0)

HashMap很简单,因为您希望从查询名称/键映射到查询/值。任何地图都可以。

public class Queries extends HashMap {
    public Queries() {
        add("My long query",
            "Super long..."+
            "...long long..."+
            "...long query.");
        // add others
    }
}

如果你想让它保持静止,你可以使用单身。

public class Queries {
    private static HashMap store = new HashMap();
    {
        // constructor
        add("My long query",
            "Super long..."+
            "...long long..."+
            "...long query.");
        // add others
    }
    public String getQuery(String queryName) { return store.get(queryName); }

或者你可以按照djna的建议使用静态字符串:

public class Queries {
    final public static myQuery = "My long query";
}

public class MyProgram extends Queries {
    ...
    public void someMethod() {
        ...
        doQuery(myQuery);
        ...
    }
}

答案 5 :(得分:0)

问题可能在于您的应用程序结构。您是否将java类分为“dao”,“service”等包?

如果您整理了项目,则无需致电ResultSet rs = statement.executeQuery( all_queries.getQuery("The very long one") ),而是致电Result res = dao.getSomethingYouNeed(param1, param2, ...);

答案 6 :(得分:0)

如果我们在文本文件中写入多个查询(而不是在属性文件中),我们可以从中检索或获取单个查询。

答案 7 :(得分:-1)

MyBatis开箱即用,就像冠军一样!