programing

Prepared Statement의 SQL을 입수하려면 어떻게 해야 합니까?

randomtip 2022. 7. 16. 15:13
반응형

Prepared Statement의 SQL을 입수하려면 어떻게 해야 합니까?

다음 메서드 시그니처를 가진 일반적인 Java 메서드가 있습니다.

private static ResultSet runSQLResultSet(String sql, Object... queryParams)

되어 「」가 됩니다.PreparedStatement및 "sql" 파라미터 queryParamsarray,, " " " " " , " " "ResultSet(a(CachedRowSetImpl 결과 를 반환합니다는 연결을 닫고 캐시된 결과 세트를 반환합니다.

오류를 기록하는 방법에는 예외 처리가 있습니다.sql 문은 디버깅에 매우 도움이 되기 때문에 로그의 일부로 기록합니다. 변수 String을 로깅하는 입니다.sql는 템플릿 문을 실제 값이 아닌 ?로 기록합니다.실행된(또는 실행하려고 시도한) 실제 을 기록합니다.

럼...에 수 있는 ? 에 의해 실행되는 실제 SQL 문을 얻을 수 있는 방법은 없습니까?PreparedStatement(직접 짓지 않고)접속 방법을 찾을 수 없는 경우PreparedStatement's SQL에 catch

준비된 문을 사용하면 "SQL 쿼리"가 없습니다.

  • 플레이스 홀더를 포함하는 스테이트먼트가 있습니다.
    • DB 서버로 전송됩니다.
    • 거기서 준비를 하고
    • 즉, SQL 문이 "분석"되고 해석되며 이를 나타내는 데이터 구조가 메모리에 준비됩니다.
  • 그리고, 당신은 묶인 변수들을 가지고 있습니다.
    • 서버에 송신됩니다.
    • 준비된 스테이트먼트가 실행됩니다.데이터에 대해 작업합니다.

그러나 Java 측에서도 데이터베이스 측에서도 실제 SQL 쿼리를 재구성할 수 없습니다.

따라서 준비된 스테이트먼트의 SQL은 없습니다.SQL은 없습니다.


은 : 버버음음음음음 음음음음음음 for for for for

  • 플레이스 홀더 및 데이터 목록과 함께 문의 코드를 출력합니다.
  • 또는 SQL 쿼리를 "수동으로" 빌드할 수도 있습니다.

되어 있지 않지만, 문제의 는 JDBC API를 만 하면 할 수 .PreparedStatement#toString()

System.out.println(preparedStatement);

MySQL 5.x 및 Postgre 이상SQL 8.x JDBC 드라이버는 이를 지원합니다.그러나 다른 대부분의 JDBC 드라이버는 지원하지 않습니다.이러한 기능이 있는 경우 Log4jdbc 또는 P6Spy를 사용하는 것이 가장 좋습니다.

일반 .Connection및하고 , 을 한다.PreparedStatement:[ ] :

public static PreparedStatement prepareStatement(Connection connection, String sql, Object... values) throws SQLException {
    PreparedStatement preparedStatement = connection.prepareStatement(sql);
    for (int i = 0; i < values.length; i++) {
        preparedStatement.setObject(i + 1, values[i]);
    }
    logger.debug(sql + " " + Arrays.asList(values));
    return preparedStatement;
}

그리고 그것을 로서

try {
    connection = database.getConnection();
    preparedStatement = prepareStatement(connection, SQL, values);
    resultSet = preparedStatement.executeQuery();
    // ...

다른 인 '하다'를 하는 것입니다.PreparedStatement그것은 진짜를 감싼다(증명한다) PreparedStatement실제의 방법을 호출할 수 있도록 모든 방법을 덮어씁니다. PreparedStatement 해서 모든 수 있습니다.setXXX() 및 SQL 은 메서드 중 가 " 언제든지 쉽게됩니다.executeXXX()메서드라고 부릅니다(대부분의 IDE는 데코레이터 메서드를 위한 자동 생성기를 제공하지만 Eclipse는 제공합니다).이치노그것은 기본적으로 P6Spy와 동료들이 이미 비밀리에 하고 있는 일이다.

MySQL 커넥터 버전 5.1.31과 함께 Java 8, JDBC 드라이버를 사용하고 있습니다.

다음 방법을 사용하여 실제 SQL 문자열을 가져올 수 있습니다.

// 1. make connection somehow, it's conn variable
// 2. make prepered statement template
PreparedStatement stmt = conn.prepareStatement(
    "INSERT INTO oc_manufacturer" +
    " SET" +
    " manufacturer_id = ?," +
    " name = ?," +
    " sort_order=0;"
);
// 3. fill template
stmt.setInt(1, 23);
stmt.setString(2, 'Google');
// 4. print sql string
System.out.println(((JDBC4PreparedStatement)stmt).asSql());

smth는 다음과 같이 반환됩니다.

INSERT INTO oc_manufacturer SET manufacturer_id = 23, name = 'Google', sort_order=0;

때 ""가 필요할 ,ResultSet 있습니다) 전화하면 .ResultSet의 »getStatement()다음과 같이 합니다.

ResultSet rs = pstmt.executeQuery();
String executedQuery = rs.getStatement().toString();

''executedQuery에는, 을 .ResultSet.

이 질문이 꽤 오래됐다는 건 알지만 누군가 도움이 됐으면 좋겠는데..

preparedStatement.toString()을 사용하여 PreparedStatement에서 SQL을 추출했습니다.이 경우 toString()은 다음과 같은 문자열을 반환합니다.

org.hsqldb.jdbc.JDBCPreparedStatement@7098b907[sql=[INSERT INTO 
TABLE_NAME(COLUMN_NAME, COLUMN_NAME, COLUMN_NAME) VALUES(?, ?, ?)],
parameters=[[value], [value], [value]]]

이제 regex를 사용하여 쿼리와 값을 모두 추출하여 맵에 표시하는 메서드(Java 8)를 만들었습니다.

private Map<String, String> extractSql(PreparedStatement preparedStatement) {
    Map<String, String> extractedParameters = new HashMap<>();
    Pattern pattern = Pattern.compile(".*\\[sql=\\[(.*)],\\sparameters=\\[(.*)]].*");
    Matcher matcher = pattern.matcher(preparedStatement.toString());
    while (matcher.find()) {
      extractedParameters.put("query", matcher.group(1));
      extractedParameters.put("values", Stream.of(matcher.group(2).split(","))
          .map(line -> line.replaceAll("(\\[|])", ""))
          .collect(Collectors.joining(", ")));
    }
    return extractedParameters;
  }

이 메서드는 키와 값의 페어가 있는 맵을 반환합니다.

"query" -> "INSERT INTO TABLE_NAME(COLUMN_NAME, COLUMN_NAME, COLUMN_NAME) VALUES(?, ?, ?)"
"values" -> "value,  value,  value"

이제 - 값을 목록으로 만들려면 다음을 사용할 수 있습니다.

List<String> values = Stream.of(yourExtractedParametersMap.get("values").split(","))
    .collect(Collectors.toList());

prepared Statement.toString()이 제 경우와 다를 경우 regex를 "조정"하는 문제일 뿐입니다.

Postgre 사용SQL 9.6.x (공식 Java 드라이버 포함)42.2.4:

...myPreparedStatement.execute...
myPreparedStatement.toString()

을 SQL로 합니다.?이미 교환이 끝난 상태고, 그게 바로 제가 찾고 있던 거예요.포스트그레스 건을 커버하기 위해 이 답변을 추가했습니다.

이렇게 간단할 줄이야

SQL PreparedStatments를 인수 목록과 함께 변환하기 위한 코드 조각입니다.난 괜찮아

  /**
         * 
         * formatQuery Utility function which will convert SQL
         * 
         * @param sql
         * @param arguments
         * @return
         */
        public static String formatQuery(final String sql, Object... arguments) {
            if (arguments != null && arguments.length <= 0) {
                return sql;
            }
            String query = sql;
            int count = 0;
            while (query.matches("(.*)\\?(.*)")) {
                query = query.replaceFirst("\\?", "{" + count + "}");
                count++;
            }
            String formatedString = java.text.MessageFormat.format(query, arguments);
            return formatedString;
        }

매우 늦었지만:) 하지만 OraclePreparedStatementWrapper에서 원본 SQL을 얻을 수 있습니다.

((OraclePreparedStatementWrapper) preparedStatement).getOriginalSql();

Prepare Statement에서 SQL을 인쇄하기 위해 다음 코드를 구현했습니다.

public void printSqlStatement(PreparedStatement preparedStatement, String sql) throws SQLException{
        String[] sqlArrya= new String[preparedStatement.getParameterMetaData().getParameterCount()];
        try {
               Pattern pattern = Pattern.compile("\\?");
               Matcher matcher = pattern.matcher(sql);
               StringBuffer sb = new StringBuffer();
               int indx = 1;  // Parameter begin with index 1
               while (matcher.find()) {
             matcher.appendReplacement(sb,String.valueOf(sqlArrya[indx]));
               }
               matcher.appendTail(sb);
              System.out.println("Executing Query [" + sb.toString() + "] with Database[" + "] ...");
               } catch (Exception ex) {
                   System.out.println("Executing Query [" + sql + "] with Database[" +  "] ...");
            }

    }

MySQL을 사용하는 경우 MySQL의 쿼리 로그를 사용하여 쿼리를 기록할 수 있습니다.다른 벤더가 이 기능을 제공하는지는 모르겠지만, 아마 제공하고 있을 것입니다.

심플한 기능:

public static String getSQL (Statement stmt){
    String tempSQL = stmt.toString();

    //please cut everything before sql from statement
    //javadb...: 
    int i1 = tempSQL.indexOf(":")+2;
    tempSQL = tempSQL.substring(i1);

    return tempSQL;
}

prepared statement도 괜찮습니다.

Oralce 11g을 사용하고 있는데 Prepared Statement에서 최종 SQL을 얻을 수 없었습니다.@Pascal MARTIN을 읽고 그 이유를 알았습니다.

저는 Prepared Statement를 사용하는 생각을 버리고 제 필요에 맞는 단순한 텍스트 포맷을 사용했습니다.예를 들어 보겠습니다.

//I jump to the point after connexion has been made ...
java.sql.Statement stmt = cnx.createStatement();
String sqlTemplate = "SELECT * FROM Users WHERE Id IN ({0})";
String sqlInParam = "21,34,3434,32"; //some random ids
String sqlFinalSql = java.text.MesssageFormat(sqlTemplate,sqlInParam);
System.out.println("SQL : " + sqlFinalSql);
rsRes = stmt.executeQuery(sqlFinalSql);

sqlInParam은 (한동안) 루프로 동적으로 구축될 수 있음을 알 수 있습니다.MessageFormat 클래스를 사용하여 SQL 쿼리의 문자열 템플릿 포메이터로 기능하는 것을 간단하게 설명했습니다.

그러기 위해서는 낮은 수준의 SQL 로깅을 지원하는 JDBC Connection 및/또는 드라이버가 필요합니다.

log4jdbc를 확인합니다.

언급URL : https://stackoverflow.com/questions/2382532/how-can-i-get-the-sql-of-a-preparedstatement

반응형