在J中构建SQL字符串的最简洁方法

我想构建一个SQL字符串来进行数据库操作(更新,删除,插入,选择,那种东西) - 而不是使用数百万" +"' s的糟糕字符串连接方法 并且报价最多是不可读的 - 必须有更好的方法。

我确实想过使用MessageFormat - 但它应该用于用户消息,虽然我认为它会做一个合理的工作 - 但我想在Java sql库中应该有一些更符合SQL类型操作的东西。

Groovy会有什么好处吗?

Vidar asked 2019-08-11T02:10:28Z
14个解决方案
67 votes

首先考虑在预准备语句中使用查询参数:

PreparedStatement stm = c.prepareStatement("UPDATE user_table SET name=? WHERE id=?");
stm.setString(1, "the name");
stm.setInt(2, 345);
stm.executeUpdate();

可以做的另一件事是将所有查询保留在属性文件中。 例如在queries.properties文件中可以放置以上查询:

update_query=UPDATE user_table SET name=? WHERE id=?

然后借助一个简单的实用程序类:

public class Queries {

    private static final String propFileName = "queries.properties";
    private static Properties props;

    public static Properties getQueries() throws SQLException {
        InputStream is = 
            Queries.class.getResourceAsStream("/" + propFileName);
        if (is == null){
            throw new SQLException("Unable to load property file: " + propFileName);
        }
        //singleton
        if(props == null){
            props = new Properties();
            try {
                props.load(is);
            } catch (IOException e) {
                throw new SQLException("Unable to load property file: " + propFileName + "\n" + e.getMessage());
            }           
        }
        return props;
    }

    public static String getQuery(String query) throws SQLException{
        return getQueries().getProperty(query);
    }

}

您可以使用以下查询:

PreparedStatement stm = c.prepareStatement(Queries.getQuery("update_query"));

这是一个相当简单的解决方案,但效果很好。

Piotr Kochański answered 2019-08-11T02:11:08Z
58 votes

对于任意SQL,请使用jOOQ。 jOOQ目前支持SELECT,INSERT,UPDATE,DELETE,TRUNCATEMERGE.您可以像这样创建SQL:

String sql1 = DSL.using(SQLDialect.MYSQL)  
                 .select(A, B, C)
                 .from(MY_TABLE)
                 .where(A.equal(5))
                 .and(B.greaterThan(8))
                 .getSQL();

String sql2 = DSL.using(SQLDialect.MYSQL)  
                 .insertInto(MY_TABLE)
                 .values(A, 1)
                 .values(B, 2)
                 .getSQL();

String sql3 = DSL.using(SQLDialect.MYSQL)  
                 .update(MY_TABLE)
                 .set(A, 1)
                 .set(B, 2)
                 .where(C.greaterThan(5))
                 .getSQL();

您也可以使用jOOQ执行它,而不是获取SQL字符串。 看到

[http://www.jooq.org]

(免责声明:我为jOOQ背后的公司工作)

Lukas Eder answered 2019-08-11T02:11:50Z
14 votes

您应该考虑的一种技术是SQLJ - 一种直接在Java中嵌入SQL语句的方法。 举个简单的例子,你可能在名为TestQueries.sqlj的文件中有以下内容:

public class TestQueries
{
    public String getUsername(int id)
    {
        String username;
        #sql
        {
            select username into :username
            from users
            where pkey = :id
        };
        return username;
    }
}

还有一个额外的预编译步骤,它将您的.sqlj文件转换为纯Java - 简而言之,它会查找与之分隔的特殊块

#sql
{
    ...
}

并将它们转换为JDBC调用。 使用SQLJ有几个主要好处:

  • 完全抽象出JDBC层 - 程序员只需要考虑Java和SQL
  • 可以使编译器在编译时针对数据库检查查询语法等
  • 能够使用"直接绑定查询中的Java变量:" 字首

大多数主要数据库供应商都有翻译器的实现,因此您应该能够轻松找到所需的一切。

Ashley Mercer answered 2019-08-11T02:12:57Z
12 votes

我想知道你是不是喜欢Squiggle之类的东西。 另外一些非常有用的东西是jDBI。 它不会帮助你解决问题。

tcurdt answered 2019-08-11T02:13:23Z
9 votes

我会看一下Spring JDBC。 每当我需要以编程方式执行SQL时,我就会使用它。 例:

int countOfActorsNamedJoe
    = jdbcTemplate.queryForInt("select count(0) from t_actors where first_name = ?", new Object[]{"Joe"});

它对任何类型的sql执行都非常有用,尤其是查询; 它可以帮助您将结果集映射到对象,而不会增加完整ORM的复杂性。

Bent André Solheim answered 2019-08-11T02:13:56Z
5 votes

我倾向于使用Spring的命名JDBC参数,所以我可以编写一个标准字符串,例如" select * from blah where colX =':someValue'&#34 ;; 我觉得这很可读。

另一种方法是在单独的.sql文件中提供字符串,并使用实用程序方法读取内容。

哦,也值得一看Squill:[https://squill.dev.java.net/docs/tutorial.html]

GaryF answered 2019-08-11T02:14:35Z
4 votes

为什么要手动生成所有的sql? 您是否看过像Hibernate这样的ORM根据您的项目,它可能至少可以完成您需要的95%,以更简洁的方式执行原始SQL,如果您需要获得最后一点性能,您可以创建 需要手动调优的SQL查询。

Jared answered 2019-08-11T02:15:03Z
4 votes

我推荐使用像Hibernate这样的ORM。 但是,肯定有些情况不起作用,所以我借此机会宣传一些我曾帮助写过的东西:SqlBuilder是一个用于动态构建sql语句的java库。"助洗剂" 样式。 它相当强大且相当灵活。

james answered 2019-08-11T02:15:30Z
3 votes

您还可以查看MyBatis(www.mybatis.org)。 它可以帮助您在Java代码之外编写SQL语句,并将sql结果映射到java对象等。

joshua answered 2019-08-11T02:15:57Z
3 votes

Google提供了一个名为Room Persistence Library的库,它提供了一种非常简洁的sql编写方式。 Bellow是官方网站的简短代码片段:

@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    List<User> getAll();

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    List<User> loadAllByIds(int[] userIds);

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND "
           + "last_name LIKE :last LIMIT 1")
    User findByName(String first, String last);

    @Insert
    void insertAll(User... users);

    @Delete
    void delete(User user);
}

图书馆的官方文档中有更多示例和更好的文档。

还有一个名为MentaBean的Java ORM。 它具有很好的功能,似乎是编写SQL的非常简单的方法。

CasualCoder3 answered 2019-08-11T02:16:36Z
2 votes

我一直在研究一个Java servlet应用程序,它需要为特殊报告目的构建非常动态的SQL语句。 该应用程序的基本功能是将一堆命名的HTTP请求参数提供给预编码的查询,并生成格式良好的输出表。 我使用Spring MVC和依赖注入框架将我的所有SQL查询存储在XML文件中,并将它们与表格格式信息一起加载到报告应用程序中。 最终,报告要求变得比现有参数映射框架的功能更复杂,我必须自己编写。 这是一个有趣的开发练习,并且为参数映射生成了一个比我能找到的任何其他东西更强大的框架。

新参数映射看起来如下:

select app.name as "App", 
       ${optional(" app.owner as "Owner", "):showOwner}
       sv.name as "Server", sum(act.trans_ct) as "Trans"
  from activity_records act, servers sv, applications app
 where act.server_id = sv.id
   and act.app_id = app.id
   and sv.id = ${integer(0,50):serverId}
   and app.id in ${integerList(50):appId}
 group by app.name, ${optional(" app.owner, "):showOwner} sv.name
 order by app.name, sv.name

最终框架的优点在于它可以通过正确的类型检查和限制检查将HTTP请求参数直接处理到查询中。 输入验证不需要额外的映射。 在上面的示例查询中,参数名为serverId将被检查以确保它可以转换为整数并且在0-50的范围内。 参数appId将作为整数数组处理,长度限制为50.如果字段showOwner存在并设置为&#34; true&#34;,引号中SQL的位将添加到生成的 查询可选的字段映射。 字段还有几个参数类型映射可用,包括带有进一步参数映射的SQL的可选段。 它允许开发人员提出的查询映射的复杂性。 它甚至在报告配置中具有控件,以确定给定查询是通过PreparedStatement进行最终映射还是仅作为预构建查询运行。

对于示例Http请求值:

showOwner: true
serverId: 20
appId: 1,2,3,5,7,11,13

它会产生以下SQL:

select app.name as "App", 
       app.owner as "Owner", 
       sv.name as "Server", sum(act.trans_ct) as "Trans"
  from activity_records act, servers sv, applications app
 where act.server_id = sv.id
   and act.app_id = app.id
   and sv.id = 20
   and app.id in (1,2,3,5,7,11,13)
 group by app.name,  app.owner,  sv.name
 order by app.name, sv.name

我真的认为Spring或Hibernate或其中一个框架应提供更强大的映射机制来验证类型,允许复杂的数据类型,如数组和其他此类功能。 我只是为了我的目的而编写了我的引擎,对于一般版本来说它并不完全可读。 它目前仅适用于Oracle查询,并且所有代码都属于大公司。 有一天,我可能会采纳我的想法,并建立一个新的开源框架,但我希望现有的大型企业之一能够接受挑战。

Natalia answered 2019-08-11T02:17:42Z
2 votes

读取XML文件。

您可以从XML文件中读取它。 它易于维护和使用。有标准的STaX,DOM,SAX解析器可以在java中使用几行代码。

使用属性做更多事情

您可以在标记上包含一些带有属性的语义信息,以帮助您更好地使用SQL。 这可以是方法名称或查询类型,也可以是帮助您减少编码的任何内容。

保养

您可以将xml放在jar外面并轻松维护它。 与属性文件相同的好处。

转变

XML是可扩展的,可以轻松转换为其他格式。

用例

Metamug使用xml来配置带有sql的REST资源文件。

Sorter answered 2019-08-11T02:19:06Z
1 votes

如果将SQL字符串放在属性文件中然后读取,则可以将SQL字符串保存在纯文本文件中。

这并没有解决SQL类型问题,但至少它使得从TOAD或sqlplus复制和粘贴变得更加容易。

Rowan answered 2019-08-11T02:19:39Z
0 votes

除了PreparedStatements中的长SQL字符串(您可以轻松地在文本文件中提供并作为资源加载)之外,您如何获得字符串连接?

你不是直接创建SQL字符串吗? 这是编程中最大的禁忌。 请使用PreparedStatements,并提供数据作为参数。 它大大降低了SQL注入的几率。

JeeBee answered 2019-08-11T02:20:13Z
translate from https://stackoverflow.com:/questions/370818/cleanest-way-to-build-an-sql-string-in-java