我们有以下代码:
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 问题的人。
答案 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
。它可以让你完全按照自己想要的方式完成,但是更清洁。