【问题标题】:Java SQL Escape without using setString不使用 setString 的 Java SQL Escape
【发布时间】:2011-07-13 14:32:53
【问题描述】:

是否有内置方法可以为 SQL 转义字符串?我会使用 setString,但碰巧我在同一个组合 SQL 语句中多次使用 setString,如果转义只发生一次而不是每次我说 setString 时,性能会更好(我认为)。如果我在变量中有转义字符串,我可以重复使用它。

在 Java 中没有办法做到这一点吗?

当前方法,多源搜索。实际上,它们是三个完全不同的 where 语句,包括连接,但在本例中,我将只显示每个表的相同 where 语句。

String q = '%' + request.getParameter("search") + '%';
PreparedStatement s = s("SELECT a,b,c FROM table1 where a = ? UNION select a,b,c from table2 where a = ? UNION select a,b,c FROM table3 where a = ?");
s.setString(1, q);
s.setString(2, q);
s.setString(3, q);
ResultSet r = s.executeQuery();

我知道这没什么大不了的,但我喜欢让事情变得高效,而且在某些情况下使用" + quote(s) + " 而不是? 更易读,然后在某处找到setString .

【问题讨论】:

  • 你想逃避什么角色?
  • 向我们展示您的一些代码会对您有所帮助。
  • @RMT: 所有被setString转义的字符我不希望由于搜索值而导致注入攻击或语法错误的可能性。

标签: java sql string escaping


【解决方案1】:

如果您将setString 用作参数(例如PreparedStatement.setString),则很可能不需要实际转义 - 数据可能会与 SQL 本身分开传递,以一种不需要的方式逃跑。

您是否有任何具体迹象表明这确实是一个性能瓶颈?在数据库查询中,代价高昂的部分似乎不太可能是在本地设置参数...

【讨论】:

  • 不太可能。这里没有瓶颈。我只是喜欢a)高效的代码和b)有时它更具可读性。请参阅我编辑的最后一部分。
  • @George:实际上,我不同意可读性 - 因为使用准备好的语句,您将 codedata 分开。但我同意命名参数比位置参数更具可读性:)
【解决方案2】:

简短的回答:我不会打扰。最好在最后一刻逃跑。当您尝试尽早转义一个字符串并保留它时,要验证所有字符串是否都被转义一次变得更加困难。 (转义字符串两次几乎和根本不转义一样糟糕!)我见过很多程序试图提前转义字符串然后遇到麻烦,因为它们需要更新字符串然后程序员忘记重新 -进行转义,或者他们更新字符串的转义版本,或者他们有四个字符串并且他们转义其中的三个,等等。(我只是在处理一个程序员早期对字符串进行 HTML 转义的错误,然后决定他必须截断字符串以适应表单,并最终尝试输出以“&am”结尾的字符串。也就是说,他截断了他的转义序列,因此它不再有效。)

转义字符串的 CPU 时间应该是微不足道的。除非您有大量的记录或非常大的字符串可以重复使用,否则我怀疑节省的费用是否值得担心。花时间优化查询可能会更好:保存一条记录的读取可能比通过字符串转义逻辑消除 1000 次行程更有价值。

更长的答案:没有内置函数。您可以很容易地编写一个:大多数 SQL 风格只需要您将任何单引号加倍。您可能还需要双反斜杠或一两个其他特殊字符。这在 SQL 引擎之间可能有所不同这一事实是使用 PreparedStatements 并让 JDBC 担心它的一大论据。 (我个人认为应该有一个 JDbC 函数来进行转义,然后可以知道特定于 DB 引擎的任何要求。但事实并非如此。)

无论如何,尚不清楚它如何与 PreparedStatement 一起工作。必须有某种方法告诉 PreparedStatement 不要转义这个字符串,因为它已经被转义了。谁真正知道在 JDBC 和 DB 引擎之间的对话中表下发生了什么:也许它根本没有真正逃避它,而是将它与查询分开传递。我想在 setString 上可能有一个额外的参数,上面写着“这个字符串是预先转义的”,但这会增加复杂性和潜在的错误,而收益很小。

【讨论】:

  • 为什么较长的答案看起来比简短的答案要短:S +1 以获得良好的描述性答案
  • @RMT:因为我不能不理会事情,所以我一直在回过头来补充我的简短回答!
【解决方案3】:

不要使用org.apache.commons.lang.StringEscapeUtils.escapeSql(yourUnscapedSQL);

它不会转义像\这样的字符

【讨论】:

  • 这会更好作为对原始问题的评论。它并没有真正回答问题
  • 应该进行修改以获得使用 StringEscapeUtils.escapeSql 的所有建议(imo 的命名非常危险 - 正如 Kim 指出的那样,它不能正确地转义 sql)。任何试图在生产中依赖 StringEscapeUtils 的人都会失败。
【解决方案4】:

您可以使用来自 Apache commons 的 StringEscapeUtils

org.apache.commons.lang.StringEscapeUtils.escapeSql(yourUnscapedSQL);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-26
    • 1970-01-01
    • 2021-07-28
    • 2017-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多