用Java构buildSQLstring的最简单的方法
我想要构build一个SQLstring来执行数据库操作(更新,删除,插入,select,这样的事情) – 而不是糟糕的stringconcat方法使用数以百万计的“+”和引号,这是最难读的 – 那里一定是一个更好的方法。
我曾考虑使用MessageFormat – 但它应该用于用户消息,虽然我认为它会做一个合理的工作 – 但我想应该有更多的东西在java sql库中的SQLtypes的操作。
Groovy会有什么好处?
首先考虑在准备好的语句中使用查询参数:
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"));
这是一个相当简单的解决scheme,但效果很好。
对于任意SQL,请使用jOOQ 。 jOOQ当前支持SELECT
, INSERT
, UPDATE
, DELETE
, TRUNCATE
和MERGE
。 你可以像这样创buildSQL:
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();
而不是获得SQLstring,你也可以使用jOOQ来执行它。 看到
(免责声明:我为jOOQ背后的公司工作)
你应该考虑的技术之一是SQLJ–一种直接在Java中embeddedSQL语句的方法。 作为一个简单的例子,你可能在一个名为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
- 可以在编译时使翻译器对数据库检查语法等查询
- 能够使用“:”前缀在查询中直接绑定Javavariables
大多数主要数据库供应商都有翻译器的实现,所以你应该能够轻松find你需要的一切。
我想知道你是否像Squiggle之类的东西。 另外一些非常有用的是jDBI 。 尽pipe如此,它不会帮助你。
我会看看Spring JDBC 。 每当我需要以编程方式执行SQL时,我都会使用它。 例:
int countOfActorsNamedJoe = jdbcTemplate.queryForInt("select count(0) from t_actors where first_name = ?", new Object[]{"Joe"});
对于任何types的sql执行都非常好,特别是查询; 它将帮助您将结果集映射到对象,而不会增加完整ORM的复杂性。
我倾向于使用Spring的命名JDBC参数,所以我可以写一个标准的string,如“select * from blah where colX =':someValue'”; 我认为这很可读。
另一种方法是在单独的.sql文件中提供string,并使用实用程序方法读取内容。
哦,还有值得看一下Squill: https ://squill.dev.java.net/docs/tutorial.html
为什么你想手工生成所有的SQL? 你是否看过像Hibernate一样的ORM?根据你的项目,它可能至less有95%的你需要,做一个干净的方式,然后原始的SQL,如果你需要获得最后一点的性能,你可以创buildSQL查询需要手动调整。
我第二次推荐使用像Hibernate这样的ORM。 然而,在某些情况下,这是行不通的,所以我将借此机会吹捧一些我曾经写过的东西: SqlBuilder是一个使用“构build器”风格dynamic构buildsql语句的java库。 它相当强大,相当灵活。
你也可以看看MyBatis( http://www.mybatis.org )。 它可以帮助您在您的Java代码之外编写SQL语句,并将SQL结果映射到您的Java对象中。
我一直在研究一个Java servlet应用程序,这个应用程序需要构build非常dynamic的SQL语句来实现特定的报告目的。 该应用程序的基本function是将一堆已命名的HTTP请求参数提供给一个预先编码的查询,并生成一个很好的输出格式表。 我使用Spring MVC和dependency injection框架将所有的SQL查询存储在XML文件中,并将它们与表格格式信息一起加载到报告应用程序中。 最终,报告要求比现有的参数映射框架的function变得更复杂,我不得不自己编写。 在开发过程中这是一个有趣的练习,并且产生了一个参数映射的框架,比我能find的其他任何东西都强大得多
新的参数映射如下所示:
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
结果框架的美妙之处在于它可以通过适当的types检查和限制检查直接将HTTP请求参数处理到查询中。 inputvalidation不需要额外的映射。 在上面的示例查询中,将检查名为serverId的参数,以确保它可以转换为整数,范围在0-50之间。 参数appId将作为整数数组处理,长度限制为50.如果showOwner字段存在且设置为“true”,则引号中的SQL位将添加到生成的可选字段查询中映射。 字段可以使用几个更多的参数types映射,包括SQL的可选分段以及更多的参数映射。 它允许像开发人员可以提出的查询映射一样复杂。 它甚至在报表configuration中具有控件,以确定给定的查询是否通过PreparedStatement具有最终的映射,或者只是作为预先构build的查询来运行。
对于示例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或者其中的一个框架应该提供更强大的映射机制来validationtypes,允许像数组和其他类似的复杂数据types。 我只是为了自己的目的而写了我的引擎,对于一般的发行版来说,它并不完全。 它只适用于Oracle查询,所有的代码都属于一个大公司。 有一天,我可以采取我的想法,并build立一个新的开源框架,但我希望现有的大玩家之一将接受挑战。
读取一个XML文件。
您可以从XML文件中读取它。 它易于维护和使用。 在那里有标准的STaX,DOM,SAXparsing器,使它在java中的几行代码。
做更多的属性
您可以在标签上添加一些带有属性的语义信息,以帮助更多地使用SQL。 这可以是方法名称或查询types或任何可以帮助您减less代码的方法。
Maintaince
您可以将xml放在jar外面,并轻松维护它。 与属性文件相同的好处。
转变
XML是可扩展的,可以轻松转换为其他格式。
用例
Metamug使用xml来configurationSQL的REST资源文件。
如果将SQLstring放在一个属性文件中,然后读取它,则可以将SQLstring保存为纯文本文件。
这并不能解决SQLtypes的问题,但至less可以使TOAD或sqlplus的复制和粘贴变得更容易。
Google提供了一个名为Room Persitence Library的库 ,它提供了一种非常干净的编写sql的方法。 贝娄是从官方网站短代码片段:
@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 。 它有很好的function,似乎是写SQL的非常简单的方法。
除了PreparedStatements中的长SQLstring(您可以轻松地在文本文件中提供并作为资源加载),如何分割string连接?
你不是直接创buildSQLstring吗? 这是编程中最大的禁忌。 请使用PreparedStatements,并提供数据作为参数。 这大大降低了SQL注入的机会。