我有几个实例,其中遗留sql语句的一部分基于依赖项。例如。
if (x !=null)
{
SQL = "SELECT z WHERE x > y";
}
else
{
SQL = "SELECT z WHERE x <= y";
}
SQL2 = SQL + " JOIN a ON b";
我正在使用此遗留代码创建PreparedStatements。这里最好的做法是什么?我是否应该为var SQL创建一个PreparedStatement并将其嵌入SQL2中,如果有多个基于SQL2的PreparedStatements没有嵌套,或者某些东西完全不同?
代码比示例复杂得多,因为SQL var在许多冗长而复杂的SQL查询中被重用。
编辑:项目设计需要使用PreparedStatements,我现在无法选择使用库。
答案 0 :(得分:4)
&gt;我应该为var SQL创建PreparedStatement并将其嵌套在SQL2
中没有
&gt;或者是否应该有多个基于SQL2的PreparedStatements而不嵌套
是
此外:如果您可以为每个查询创建一个更好的字符串。我真的不喜欢将SQL与代码混合在一起。它使调试和理解变得更加困难,您无法复制/粘贴到SQL工具来轻松地进行测试。通过将SQL与代码分开,您可以将查询与操作(实际提取)隔离开来,并且更容易维护。此外,如果代码不是你的,那么理解起来会容易得多。
看起来你的重复字符串并不重要,重点是尽可能地简化陈述。
我会做这样的事情:
final class DatabaseQueries {
public final static String SOME_SCENARIO = "SELECT z WHERE x > y JOIN A, B ";
public final static String SOME_OTHER_SCENARIO = "SELECT z WHERE x <= y JOIN A, B";
}
然后在课堂上使用它:
PreparedStatement pstmt = getCon().prepareStatement( getQuery() );
private String getQuery() {
if( x != null ) {
return DatabaseQueries.SOME_SCENARIO;
} else {
return DatabaseQueries.SOME_OTHER_SCENARIO;
}
}
在创建“DatabaseQueries”类时,你会发现你重复了很多字符串,我认为用其他常量来支持某些部分会很好。
final class DataBaseQueries {
// this one is private
private final static String JOIN_A_B = " join A, B ";
public final static String SOME_SCENARIO = "SELECT z WHERE x > y " + JOIN_A_B ;
public final static String SOME_OTHER_SCENARIO = "SELECT z WHERE x <= y " + JOIN_A_B ;
}
这里的要点是让事情变得简单。这是第一步。在第二步中,您可以创建一个类来创建那些非常复杂的查询,但可能是YAGNI。
如果查询过多,您可以将其替换为从ResourceBundle中加载它们,例如question
我希望这会有所帮助。
答案 1 :(得分:2)
Ibatis非常擅长这一点。
<select id="queryName" parameterClass="com.blah.X"><!<[CDATA[
SELECT z
FROM a
JOIN b ON a.id = b.foreign_key
WHERE
<isNotNull property="value">
x > y
</isNotNull>
<isNull property="value">
x <= y
</isNull>
]]></select>
这只是Ibatis可以做的一小部分,但它非常轻巧。优秀的技术。
答案 2 :(得分:1)
这不是正确使用预准备语句参数。只能使用参数代替SQL表达式中的文字值。不是表名,列名或其他SQL语法。
您可以使用某些库来构建SQL查询的一部分。我在PHP中使用这个库,名为Zend_Db_Select
。
编辑:我搜索了一个类似的Java库,我发现这个选项可能会有所帮助:
它是免费的,并根据Apache许可证提供,这是一个非常灵活的开源许可证。
谷歌搜索“java查询构建器”发现了许多其他选项,但有些不是免费的。有些是可视化查询构建器,而不是程序化查询构建器。
另一种选择是使用像Hibernate这样复杂的对象关系映射框架,但这对你当前的任务来说似乎有些过分。
答案 3 :(得分:0)
简短的回答 - 没有最好的方法。你可能会得到这样的结论:
String selectQuery =
(new SelectQuery())
.addColumns(t1Col1, t1Col2, t2Col1)
.addJoin(SelectQuery.JoinType.INNER_JOIN, joinOfT1AndT2)
.addOrderings(t1Col1)
.validate().toString();
但对我来说情况更糟。
答案 4 :(得分:0)
我想一方面有一种纯粹的对象方法,如果你试图理解遗留代码,这可能不会对你有很大的帮助。我发现,在重构真正讨厌的遗留代码而不是追求“完美”时,通常更好,更容易,简化小块,模块化和文档记录,因为你可以在不重写整个应用程序的情况下制作它们。我发现重构坏代码对我来说最大的障碍是,如果我采取太大的步骤,我就不能再相信我没有破坏任何东西 - 如果它是那么糟糕,可能没有单元测试,并且可能存在未定义或未记录的行为。
我至少会将逻辑和sql作为第一遍传递出去。你不想要的东西是这样的:
String sql = "yadda yadda yadda ? yadda yadda WHERE ";
if (mystery condition 1){
sql = sql + " page=?"
}
else if (mystery condition 2)
{
sql = sql + " ORDER BY ? "
}
过了一段时间,你将无法分辨出正在构建的语句。不值得保存复制初始sql的位。它可能更容易理解为:
private static final String FIND_PAGE_QUERY = "...."
private static final String ORDER_BY_QUERY =" ..."
if (mystery condition 1){
return process(FIND_PAGE_QUERY, parameters);
}
else if (mystery condition 2)
{
return process(ORDER_BY_QUERY, parameters);
}
然后只需创建一些内容来包装您的查询和传递的参数,如Spring JDBC Row Mappers或类似的东西。这仍然是丑陋的,但它很容易做到从你所拥有的增量步骤,并将至少解决一些查询生成的混乱。
答案 5 :(得分:0)
另一种方法是将条件移动到SQL语句本身,这样您只需要一个语句。它会是这样的:
SELECT z WHERE (? IS NOT NULL AND x > y) OR (? IS NULL AND x <= y)
然后为参数绑定适当的值。
不确定这是最好的方法......人们可能会发现代码不太清楚。但这是一种可能性。