将问号替换为相应的参数字符串。

huangapple go评论77阅读模式
英文:

Replace question mark with respective parameter string

问题

我有一个如下的SQL查询,并且我想用传递的相应绑定参数来替换问号。我该如何构建这个字符串?

select this_.id, this_.name from table this_ where this_.depId = ? and this_.perStatus = ?

我想要像下面这样替换问号:

select this_.id, this_.name from table this_ where this_.depId = 10 and this_.perStatus = 'Active'

我该如何替换所有的问号以及相应的参数。任何帮助都将不胜感激。

英文:

I have a sql query like below and I want to replace the question mark with respective binded parameters passed. How will I construct this String

select this_.id, this_.name from table this_ where this_.depId = ? and this_.perStatus = ?

I want to replace the question mark like below

select this_.id, this_.name from table this_ where this_.depId = 10 and this_.perStatus = 'Active'

How do I replace all the question marks with respective parameters.
Any help appreciated.

答案1

得分: 2

以下是您要翻译的代码部分:

如果我们同意这不应该用于构造Statement”,而只用于调试消息您可以这样做

static final Pattern COMPARISON = Pattern.compile("((\\w+)\\s*[<>=]+\\s*)\\?");

static String debugExpression(String actualQuery, Map<String, Object> values) {
    return COMPARISON.matcher(actualQuery)
        .replaceAll(mr -> mr.group(1) + forValue(values.get(mr.group(2))));
}

private static String forValue(Object o) {
    return o instanceof Number || o instanceof Boolean? o.toString():
        o == null? " *** key not in map ***":
        "'" + Matcher.quoteReplacement(o.toString()) + "'";
}

这段代码搜索“名称 比较运算符 问号”的出现并将问号替换为在映射中找到的“名称”的值的表示形式。

如果您希望强制要求“名称”前缀为 this_.,则可以使用以下模式:

static final Pattern COMPARISON
    = Pattern.compile("(?<=this_\\.)((\\w+)\\s*[<>=]+\\s*)\\?");

如果我们使用以下方式测试它

String query = "select this_.id, this_.name from table this_ where this_.depId = ? and this_.perStatus = ?";
System.out.println(debugExpression(query, Map.of("depId", 10, "perStatus", "Active")));

它将打印

select this_.id, this_.name from table this_ where this_.depId = 10 and this_.perStatus = 'Active'

这不会替换其他问号,比如更新或插入语句的 (?, ? …),因为没有上下文来推断正确的键。


上面的代码使用了Java 9的功能。如果您需要Java 8的兼容性,替换逻辑需要手动实现:

static String debugExpression(String actualQuery, Map<String, Object> values) {

  Matcher m = COMPARISON.matcher(actualQuery);
  if(!m.find()) return actualQuery;

  StringBuilder sb = new StringBuilder(actualQuery.length() + 100);
  int start = 0;

  do {
    sb.append(actualQuery, start, m.end(1));
    start = m.end();
    Object o = values.get(m.group(2));

    if(o == null) sb.append(" *** key not in map ***");
    else if(o instanceof Number || o instanceof Boolean) sb.append(o);
    else sb.append("'").append(o).append("'");

  } while(m.find());

  return sb.append(actualQuery, start, actualQuery.length()).toString();
}

希望这些帮助!

英文:

If we agree that this should never be used to construct a Statement but only for debugging messages, you can do it like

static final Pattern COMPARISON = Pattern.compile(&quot;((\\w+)\\s*[&lt;&gt;=]+\\s*)\\?&quot;);

static String debugExpression(String actualQuery, Map&lt;String,Object&gt; values) {
    return COMPARISON.matcher(actualQuery)
        .replaceAll(mr -&gt; mr.group(1) + forValue(values.get(mr.group(2))));
}

private static String forValue(Object o) {
    return o instanceof Number || o instanceof Boolean? o.toString():
        o == null? &quot; *** key not in map ***&quot;:
        &quot;&#39;&quot; + Matcher.quoteReplacement(o.toString()) + &quot;&#39;&quot;;
}

This searches for occurrences of “name  comparison operator  question mark” and replaces the question mark with a representation of the value found in the map for “name”.

If you prefer to enforce the “name” to be prepended by this_. you can use the following pattern instead:

static final Pattern COMPARISON
    = Pattern.compile(&quot;(?&lt;=this_\\.)((\\w+)\\s*[&lt;&gt;=]+\\s*)\\?&quot;);

If we test it with

String query = &quot;select this_.id, this_.name from table this_ where this_.depId = ? and this_.perStatus = ?&quot;;
System.out.println(debugExpression(query, Map.of(&quot;depId&quot;, 10, &quot;perStatus&quot;, &quot;Active&quot;)));

It will print

select this_.id, this_.name from table this_ where this_.depId = 10 and this_.perStatus = &#39;Active&#39;

This will not replace other question marks, like the (?, ? …) of an update or insert statement, as there’s no context to derive the right key from.


The code above uses Java 9 features. If you need Java 8 compatibility, the replacement logic needs to be implemented manually:

static String debugExpression(String actualQuery, Map&lt;String,Object&gt; values) {

  Matcher m = COMPARISON.matcher(actualQuery);
  if(!m.find()) return actualQuery;

  StringBuilder sb = new StringBuilder(actualQuery.length() + 100);
  int start = 0;

  do {
    sb.append(actualQuery, start, m.end(1));
    start = m.end();
    Object o = values.get(m.group(2));

    if(o == null) sb.append(&quot; *** key not in map ***&quot;);
    else if(o instanceof Number || o instanceof Boolean) sb.append(o);
    else sb.append(&quot;&#39;&quot;).append(o).append(&quot;&#39;&quot;);

  } while(m.find());

  return sb.append(actualQuery, start, actualQuery.length()).toString();
}

答案2

得分: 1

常规方式(易受注入攻击)

String depId = "10";
String perStatus = "'Active'";

String query = "select this_.id, this_.name from table this_ where this_.depId = %s and this_.perStatus = %s";
String finalQuery = String.format(query, depId, perStatus);

System.out.println(finalQuery);

安全方式(PreparedStatement)

String query = "select this_.id, this_.name from table this_ where this_.depId = ? and this_.perStatus = ?";
PreparedStatement prepStatQuery = con.prepareStatement(query);

prepStatQuery.setInt(1, 10);
prepStatQuery.setString(2, "Active");

ResultSet resSet = prepStatQuery.executeQuery();
英文:

I assume you are using Java and I am not a Java-expert so hope this answer can help you a bit.

Normal way (Vulnerable to injection attack)

String depId = &quot;10&quot;;
String perStatus = &quot;&#39;Active&#39;&quot;;

String query = &quot;select this_.id, this_.name from table this_ where 
this_.depId = %s and this_.perStatus = %s&quot;;
String finalQuery = String.format(query, depId, perStatus);

System.out.println(finalQuery);

Safeway (PreparedStatement)

String query = &quot;select this_.id, this_.name from table this_ where this_.depId = ? and this_.perStatus = ?&quot;;
PreparedStatement prepStatQuery = con.prepareStatement(query);

prepStatQuery.setInt(1, 10);
prepStatQuery.setString(2, &quot;Active&quot;);

ResultSet resSet = prepStatQuery.executeQuery();

答案3

得分: 0

  1. 使用 String.format 方法 并按您想要的顺序对参数进行对齐。在这里,您将使用格式说明符替换您的 ?
  2. 使用 JDBC 您需要 PreparedStatement
  3. 或者使用 Spring Data,请查看此 链接
英文:

You have many options here:

  1. Use String.format method and align the parameters in the order you want. Here you will replace your ? with a format specifier.
  2. With JDBC you have to PreparedStatement.
  3. Or with Spring Data check this link.

答案4

得分: 0

我建议您在您的情况下使用存储过程。它们很容易创建,并直接存储在您的数据库中。您的存储过程可能如下所示。

CREATE PROCEDURE yourProcedureName
    @depId int,
    @perStatus varchar(10)
AS
BEGIN
    SELECT this_.id, this_.name from table this_ where this_.depId = @depId and this_.perStatus = @perStatus
END

以下是一些示例,您如何在您的Java代码中调用您的存储过程。

public void storedProcedure(int depId, String perStatus, String connectionUrl){
    Connection con = null;
    PreparedStatement pStatement = null;
    ResultSet rs = null;

    try {
        // 建立连接
        Connection connection = DriverManager.getConnection(connectionUrl);

        // 准备存储过程调用
        String storedProcedure = "{CALL yourProcedureName(?,?)}";
        pStatement = connection.prepareCall(storedProcedure);

        pStatement.setInt(1, depId);
        pStatement.setString(2, perStatus);

        pStatement.execute();

        pStatement.close();
        connection.close();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        if (rs != null) try {
            rs.close();
        } catch (Exception e) {}
        if (pStatement != null) try {
            pStatement.close();
        } catch (Exception e) {}
        if (con != null) try {
            con.close();
        } catch (Exception e) {}
    }
}
英文:

I would suggest you to use Stored Procedures in you're Case.
They are easy to create and are stored on you're Database directly.
You're Stored Procedure could look like this.

CREATE PROCEDURE yourProcedureName
	@depId int,
	@perStatus varchar(10),
	AS
	BEGIN
		SELECT this_.id, this_.name from table this_ where this_.depId = @depId and this_.perStatus = @perStatus
END

Here is some example how you could call your Stored Procedure in your Java Code.

public void storedProcedure(Int depId, String perStatus, String connectionUrl){
    Connection con = null;
    PreparedStatement pStatement = null;
    ResultSet rs = null;

    try {
        // Establish the connection
        Connection connection = DriverManager.getConnection(connectionUrl);

        // Prepare the stored procedure call
        String storedProcedure = &quot;{CALL procedureName(?,?)}&quot;;
        pStatement = connection.prepareCall(storedProcedure);

        pStatement.setInt(1,depId);
        pStatement.setString(2,perStatus);


        pStatement.execute();

        pStatement.close();
        connection.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    finally {
        if(rs != null) try {
            rs.close();
        }catch (Exception e){}
        if(pStatement!=null) try {
            pStatement.close();
        }catch (Exception e){}
        if(con!=null) try{con.close();} catch (Exception e){}
    }

}

huangapple
  • 本文由 发表于 2023年6月29日 00:49:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76575240.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定