在 Java 中构建 SQL 字符串的最干净的方法

我想构建一个 SQL 字符串来进行数据库操作(更新、删除、插入、选择之类的操作)——而不是使用数百万个“ +”和引号的糟糕的字符串 concat 方法,这种方法充其量是不可读的——必须有更好的方法。

我确实考虑过使用 MessageFormat-但它应该用于用户消息,尽管我认为它会做一个合理的工作-但我猜测应该有一些更符合 SQL 类型操作的 java SQL 库。

Groovy 有用吗?

159510 次浏览

我倾向于使用 Spring 的命名 JDBC 参数,这样我就可以编写一个标准字符串,比如“ select * from 累赘 where colX =’: some Value’”; 我认为这是非常可读的。

另一种方法是在单独的。使用实用工具方法读取 sql 文件中的内容。

Oh, also worth having a look at Squill: https://squill.dev.java.net/docs/tutorial.html

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

这并不能解决 SQL 类型的问题,但至少使得从 TOAD 或 sqlplus 进行复制和粘贴变得更加容易。

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

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

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"));

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

我想知道,如果你是后,像 弯弯曲曲(GitHub)。同样非常有用的是 JDBI。不过这对你的查询没有帮助。

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

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

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

您应该考虑的一种技术是 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
{
...
}

使用 SQLJ 有几个关键的好处:

  • 完全抽象化了 JDBC 层-程序员只需要考虑 Java 和 SQL
  • 可以让翻译器在编译时根据数据库检查您的查询语法等
  • 在查询中使用“ :”前缀直接绑定 Java 变量的能力

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

除了 PreparedStatments 中的长 SQL 字符串(可以轻松地在文本文件中提供并作为资源加载)之外,如何获得字符串串联并将其分隔成几行?

You aren't creating SQL strings directly are you? That's the biggest no-no in programming. Please use PreparedStatements, and supply the data as parameters. It reduces the chance of SQL Injection vastly.

我支持使用像 Hibernate 这样的 ORM 的建议。然而,在某些情况下,这种方法肯定是行不通的,所以我将借此机会推荐一些我曾经帮助编写的东西: SqlBuilder是一个用于使用“ Builder”风格动态构建 sql 语句的 Java 库。它相当强大,也相当灵活。

我一直在开发一个 Javaservlet 应用程序,该应用程序需要构造非常动态的 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 请求参数直接处理到查询中。输入验证不需要额外的映射。在上面的示例查询中,名为 < em > serverId 的参数 将被检查,以确保它可以转换为一个整数,并在0-50的范围。参数 应用程序将被处理为一个整数数组,长度限制为50。如果字段 主人存在并设置为“ true”,引号中的 SQL 位将被添加到生成的查询中,用于可选的字段映射。Field 还有更多的参数类型映射,包括带有更多参数映射的可选 SQL 片段。它允许开发人员提出的查询映射尽可能复杂。它甚至在报表配置中具有控件,以确定给定查询是通过 PreparedStatement 具有最终映射,还是仅仅作为预构建查询运行。

对于示例 Http 请求值:

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

It would produce the following 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 查询,所有代码都属于一家大公司。有一天,我可能会采纳自己的想法,构建一个新的开源框架,但我希望现有的一个大玩家能够接受这个挑战。

对于任意 SQL,使用 JooQ。JOOQ 目前支持 SELECTINSERTUPDATEDELETETRUNCATEMERGE。您可以像下面这样创建 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();

Instead of obtaining the SQL string, you could also just execute it, using jOOQ. See

Http://www.jooq.org

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

You can also have a look at MyBatis (www.mybatis.org) . It helps you write SQL statements outside your java code and maps the sql results into your java objects among other things.

读取 XML 文件。

您可以从 XML 文件中读取它。 有标准的 StaX、 DOM、 SAX 解析器可供选择,只需要几行 Java 代码。

使用属性进行更多操作

你可以在标签上添加一些属性语义信息来帮助你更好的使用 SQL。这可以是方法名称或查询类型,也可以是帮助您减少编码量的任何东西。

维护

您可以将 xml 放在 jar 之外并轻松地维护它。

转换

XML is extensible and easily convertible to other formats.

用例

Metamug 使用 xml 用 sql 配置 REST 资源文件。

谷歌提供了一个名为 房间持续图书馆的库,它提供了一种非常简洁的方式来编写 SQL for Android Apps,基本上就是一个底层 SQLite 数据库的抽象层。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 编写方式。