【问题标题】:Java SQL query prepare statement dynamic parameterJava SQL查询prepare语句动态参数
【发布时间】:2013-04-29 14:59:48
【问题描述】:

我正在处理使用 java 的 sql 查询,其参数可能存在或不存在于查询中。

比如有一个http请求参数为:

  1. 姓名
  2. 开始
  3. 限制

在 jsp 中,我做了这样的事情。

if (request.getParameter("query") != null) {        
  query = request.getParameter("query"); 
}

if (request.getParameter("start") != null) {
  start = Integer.parseInt(request.getParameter("start"));  
}

if (request.getParameter("limit") != null) {
  limit = Integer.parseInt(request.getParameter("limit"));  
}

....

if (query != null) {
  sql += " AND dbo.TABLENAME.namelike '%?%'";
}

if (start != null) {
  sql += " AND RowNum >= ?";
}

if (limit != null) {
  sql += " AND RowNum <= ?";
  if (start == null) 
    start =0;
}

有没有什么简单的方法可以用 PreparedStatement 做到这一点?或者有什么更清洁的方法可以做到这一点。如果我没记错的话,必须在准备好的语句中首先指定 SQL 字符串,而不是后面。

【问题讨论】:

  • 你会考虑使用IBatis还是Hibernate?
  • 就是这样,这个项目一定不能用ORM,只能用jsp。这不是我的决定,我知道这很疯狂。
  • Codemwnci 的回答是不够的,你需要考虑很多。特别要注意特殊字符。
  • 是的,我明白了,我很想使用 ORM,但我们的客户不接受。
  • 您不能使用like '%?%'。您必须使用like ? 并将% 字符放在绑定的字符串参数周围。

标签: java sql sql-server


【解决方案1】:

在您的特定情况下,您应该可以执行以下操作

sql += "AND dbo.TABLENAME.namelike '%?%' AND RowNum >= ? AND RowNum <= ?";

如果没有开始,您可以将 RowNum 设置为 0,如果没有结束,则将 RowNum 设置为 Integer.MAX_INTEGER。另外,如果没有传入任何查询,那么无论如何它都会返回所有内容。

虽然这样效率很低,所以您可以使用 CASE 语句来尝试提高效率。

【讨论】:

  • 如果有另一个参数说性别,那么查询看起来像sql += "AND dbo.TABLENAME.name like '%?%' AND gender ='F' AND RowNum &gt;= ? AND RowNum &lt;= ?";
  • 上述语句有效的唯一原因是您正在使用可以模仿不存在的元素(通过使用最大值和最小值或空值)。如果你想默认一个不存在的性别,那很好,因为你可以默认,但是如果你想忽略性别,如果没有传入,你将不得不使用 LIKE 语句,这将让它越来越低效
【解决方案2】:

为了在没有框架帮助的情况下使其更清晰,您可以将单独的查询外部化,在您的示例中,无论有无分页参数,并将它们放在属性文件中,例如 queries.properties:

query.paging=SELECT * FROM dbo.TABLENAME WHERE namelike ? AND RowNum >= ? AND RowNum <= ?
query.nopaging=SELECT * FROM dbo.TABLENAME WHERE namelike ?

然后在您的代码中区分用例并访问相应的查询:

ResourceBundle queries = ResourceBundle.getBundle("queries");

String nameLike = request.getParameter("nameLike");
String startRow= request.getParameter("startRow");
String endRow= request.getParameter("endRow");

if (nameLike == null) {        
    nameLike = ""; // or you could report an error here
}

Connection connection = ...get a JDBC Conection...

PreparedStatement st;
if (startRow != null && endRow != null) {
    st = connection.prepareStatement(queries.get("query.paging"));
    st.setString(1, nameLike);
    st.setString(2, startRow);
    st.setString(3, endRow);
}
else {
    st = connection.prepareStatement(queries.get("query.nopaging"));
    st.setString(1, nameLike);
}

使用 PreparedStatement 可以避免 SQL 注入攻击的安全风险。

【讨论】:

    【解决方案3】:

    尝试使用 SQL 标签。 JSTL 提供此 sql 标记,因为您只能使用 JSP。 它是 Java EE 标准的一部分。

    这比在 jsp 中编写 java 代码更干净、更容易。

    这是链接。 http://download.oracle.com/javaee/1.4/tutorial/doc/JSTL7.html.

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 2016-10-07
      • 2011-01-26
      • 1970-01-01
      • 2013-06-21
      • 1970-01-01
      • 2014-07-11
      • 1970-01-01
      • 2017-09-10
      • 1970-01-01
      相关资源
      最近更新 更多