有效地进行Java字符串替换

时间:2011-04-29 08:58:02

标签: java string performance replace

我们有以下代码:

String templateQuery = "select * from my_table where col1=$1 or col2 like '%$2.$1'";
String tmp = templateQuery;

for(int i=1;i<=maxCols;i++) {
    tmp = tmp.replaceAll("\\$"+i, data[i-1]);
}

这段代码工作得很好,因为maxCols永远不会超过10.但是我的同事不同意我说这段代码消耗了太多内存。你能帮助我们吗?

修改: 我已经用一个非常现实的模板更改了最初的templateQuery。其次,templateQuery可能是 big 字符串。

编辑2 : 感谢那些指出 SQLInjection 问题的人。

5 个答案:

答案 0 :(得分:6)

不要这样做。

不是出于性能原因(将 miniscule 与数据库查询的成本相比较),而是为了避免SQL注入攻击。如果data[0]实际上是字符串

,会发生什么
' OR 'x' = 'x

然后你将得到一个SQL语句:

SELECT * FROM my_table WHERE col1='' OR 'x' = 'x'
我认为我们可以同意的不是你想要的。

使用参数化的SQL语句(PreparedStatement)并获取数据库驱动程序以单独发送参数值。

编辑:在其他评论中,OP已指定模板字符串可能很长,而某些参数实际上可能涉及多个初始值组合在一起。我仍然说在更宏大的计划中替换成本可能微不足道,我仍然PreparedStatement是要走的路。在将它们设置为PreparedStatement的值之前,您应该对输入执行所需的任何组合操作 - 因此模板可能需要带有SQL占位符的SQL,然后“子模板”以确定如何从您获取输入PreparedStatement的参数。无论你做什么,将值直接放入SQL都是错误的方法。

答案 1 :(得分:3)

他是对的,因为你创建了 maxCols tmp 字符串。 我意识到它是针对Sql命令的,如果是,为什么你不使用 PreparedStatement (http://download.oracle.com/javase/1.4.2/docs/api/java/sql /PreparedStatement.html)执行此任务?

另外,为了格式化字符串,而不是使用替换,使用 Formatter ,它更优雅:http://download.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html

答案 2 :(得分:3)

为什么不使用带有替换参数的PreparedStatement

String templateQuery = "SELECT * FROM my_table WHERE col1 = ?";
PreparedStatement ps = con.prepareStatement(templateQuery);
for (int i = 0; i < data.length; i++) {
    ps.setString(i + 1, data[i]);
}
ResultSet rs = ps.executeQuery();

如果你使用像你一样的字符串替换,你就会受到SQL injection的攻击。<​​/ p>

答案 3 :(得分:0)

您的同事是对的,因为每个字符串替换都会创建一个新的字符串副本。 (但是,使用少于10个参数时,这些成本可能微不足道。)此外,对于此查询的每次执行,SQL引擎都需要重新解析它,每次都会消耗更多的额外资源。

但潜在的更大问题是代码依赖于SQL注入。如果输入数据来自外部源,黑客可以传入"col1; drop table my_table;"等参数,有效删除整个表格。

所有这些都可以通过使用PreparedStatement来解决。

答案 4 :(得分:0)

这是否会消耗过多的记忆,这是否有争议(什么是“太多”?)

尽管如此,对于这类内容,您应该使用PreparedStatement。它可以让你完全按照自己想要的方式完成,但是更清洁。