Java PreparedStatement不带逗号分隔符的多次替换

Java PreparedStatement不带逗号分隔符的多次替换,java,sql,prepared-statement,Java,Sql,Prepared Statement,我准备了以下声明: PreparedStatement statement = conn.prepareStatement("Select * from foo where foo.age ? ? AND foo.children ? ?") 现在解释一下我想做什么,因为我很懒,不喜欢写多个查询。我希望语句在完成时如下所示: Select * from foo where foo.age >= 42 AND foo.children <= 3 如果不清楚

我准备了以下声明:

  PreparedStatement statement = conn.prepareStatement("Select * from foo 
          where foo.age ? ? AND foo.children ? ?")
现在解释一下我想做什么,因为我很懒,不喜欢写多个查询。我希望语句在完成时如下所示:

Select * from foo where foo.age >= 42 AND foo.children <= 3

如果不清楚,我希望能够替换一行中的多个标记,其中第一个标记恰好是限定符equals、greater、less等,后面的标记恰好是文字3、17、Steve等。我的问题是这是否可能,如果可能,如何实现这一点?

这无法实现。PreparedStatement中的参数只能是值,不能是运算符、表名等

现在,对于上述特定查询,您可以执行以下操作:

select * from foo where age > ? and age < ? 

然后,42400岁,你的年龄>=42岁,42岁,你的年龄=42岁,你不能这么做,因为?不表示令牌,而是表示值。显然,有些标记,即文本,表示值,但即使对于这些标记,值?直接表示值本身,而不是也表示值的文本。这是设计中的一个有意元素,因为参数化查询的目的是防止参数泄漏并被解释为非单个值

编辑添加:在我工作的地方,我们有一个围绕JDBC的定制框架,可以处理事务等,所以我们通常不必直接处理PreparedStatement。该框架有一个类似以下内容的方法:

public <T> Iterator<T> executeQuery(ConverterFromResultSetToT<T> converter,
                                     String query, Map<String, Object> params)
{
    // . . . modify query, replacing any instances of $!{paramKey} with the
    //       corresponding value from params -- this allows arbitrary SQL code
    //       to be injected, in the rare cases that that's necessary

    // . . . modify query, replacing any instances of ${paramKey} with '?' and
    //       adding the corresponding value from params to an array -- we use
    //       this much more often

    // . . . create PreparedStatement with the resulting query

    // . . . set parameters of PreparedStatement from aforemented array

    // . . . run PreparedStatement; wrap result in an Iterator<T>; and return
}
但我只会在你想做很多这类事情的时候推荐这种东西。我们在这个框架中投入了大量的精力,它非常有用,但它也包含大量的代码


值得注意的是,尽管文档可能暗示了什么,创建PreparedStatement的成本并不是很高。除非您确实多次运行同一查询,否则每次重新创建PreparedStatement并不是什么大问题。因此,只要您愿意为此编写自己的代码,就不需要内置对drop-in操作符的支持。

您可以有一个解决方法:

String query = "Select * from foo where foo.age @ @ AND foo.children @ @";

//write code here to manipulate your query string using
query = query.replaceFirst("@", "=");
query = query.replaceFirst("@", "42");
query = query.replaceFirst("@", "=");
query = query.replaceFirst("@", "3");

Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query );
如果您决定如上所述使用replaceFirst,请注意您是从左到右赋值


无论如何,我认为这不是一件很优雅的事情。不编写多个查询似乎不是一个明智的设计目标。

好的,那么有没有办法允许对父语句对象进行多次替换?不知道您的意思,语句根本不允许任何参数,除非它是PreparedStatementSure。那么,使用常规语句对象可以做到这一点吗?@Woot4Moo您可以通过连接正确的运算符来创建sql字符串。但它与语句或PreparedStatement无关。我们有一个白名单功能,它将我们从了解下面的数据库实现中抽象出来,而这正是这个问题产生的原因。但是很高兴知道。为什么没有人提到在需要之前创建一个合适的预处理语句,然后马上丢弃它?这不是个好主意吗?
String query = "Select * from foo where foo.age @ @ AND foo.children @ @";

//write code here to manipulate your query string using
query = query.replaceFirst("@", "=");
query = query.replaceFirst("@", "42");
query = query.replaceFirst("@", "=");
query = query.replaceFirst("@", "3");

Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query );
String firstOperator = ">="
String secondOperator = "<="

PreparedStatement statement = conn.prepareStatement("Select * from foo 
          where foo.age "+firstOperator+" ? AND foo.children "+secondOperator+" ?");

statement.setInt(1,42);
statement.setInt(2,3);