简短的回答是:是的,假设您修复了引用,两者应该给出相同的结果。百分号不会从准备好的语句中“删除”,就像任何其他字符一样。
更长的答案:准备好的语句与一次性语句的问题可能很复杂。如果您只打算执行一次,则准备好的语句将花费更长的时间,因为数据库引擎必须为准备好的语句完成所有设置,然后插入值,然后让它在缓存中浮动,直到引擎决定冲洗它。此外,优化器通常不能有效地处理准备好的语句。准备好的语句的全部意义在于优化器解析查询并设计一次查询计划。假设您说“从 customer_type=? 和 customer_zip=? 的客户中选择 customer_name”。您对类型和 zip 都有索引。使用一次性声明(当然,填充的是真实值而不是问号),许多数据库引擎中的查询优化器可以查看关于两个字段的值分布的统计信息,并选择将提供较小记录集的索引,然后按顺序读取所有这些并消除未通过第二次测试的记录。使用准备好的语句,它必须在知道将提供什么值之前选择索引,因此它可能会选择效率较低的索引。
你永远不应该在死亡的痛苦中编写代码,只是在未知值周围加上引号并将其填充到 SQL 语句中。要么使用准备好的语句,要么编写一个正确转义任何嵌入引号的函数。这样的函数写起来很简单。我不明白为什么 JDBC 不包含一个,所以您必须自己编写它并将其包含在每个应用程序中。(鉴于某些 SQL 方言具有应转义的单引号以外的字符,这一点尤其正确。)
以下是 Java 中此类函数的示例:
public static String q(String s)
{
if (s==null)
return "null";
if (s.indexOf('\'')<0)
return "'"+s+"'";
int sl=s.length();
char[] c2=new char[sl*2+2];
c2[0]='\'';
int p2=1;
for (int p=0;p<sl;++p)
{
char c=s.charAt(p);
if (c=='\'')
c2[p2++]=c;
c2[p2++]=c;
}
c2[p2++]='\'';
return new String(c2,0,p2);
}
(注意:我刚刚从我从代码中提取的版本中编辑了该功能,以消除一些与此处无关的特殊情况——如果我在执行此操作时引入了一些小错误,请见谅。)
我通常给它一个非常短的名字,比如“q”,所以我可以写:
String sql="select customer_name from customer where customer_type="+q(custType)
+" and customer_zip="+q(custZip);
或类似的快速简单的东西。这违反了“为函数提供完整且有意义的名称”,但我认为在这里值得,我可以在一个语句中使用相同的函数十次。
然后我重载它以获取日期和数字以及其他特殊类型并适当地处理它们。