복붙노트

[SQL] 어떻게 된 PreparedStatement의 SQL을받을 수 있나요?

SQL

어떻게 된 PreparedStatement의 SQL을받을 수 있나요?

나는 다음과 같은 방법 서명 일반적인 자바 방법이있다 :

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

그것은, 연결을 여는 queryParams에서 SQL 문 및 매개 변수 가변 길이 배열을 사용하여 PreparedStatement의를 구축, 그것을 실행 (A CachedRowSetImpl에서) 결과 집합을 캐시, 연결, 반환 캐시 된 결과 집합을 닫습니다.

나는 로그 오류 그 방법에있어서 예외 처리가 있습니다. 이 디버깅에 매우 도움이 이후는 로그의 일부로서 SQL 문을 로그. 내 문제는 '? String 변수의 SQL을 기록하는 것은으로 템플릿 구문을 기록한다는 것입니다 대신 실제 값의이야. 나는 실행 (또는 실행하려고) 된 실제 문을 로그합니다.

그래서 ... 해, PreparedStatement에 의해 실행됩니다 실제 SQL 문을 얻을 수있는 방법이 있습니까? (그것을 자신을 구축하지 않고. 나는 아마 내 어획량에 나 자신을 구축하게 될 겁니다, PreparedStatement의의 SQL에 액세스 할 수있는 방법을 찾을 수없는 경우.)

해결법

  1. ==============================

    1.준비된 문을 사용하여, "SQL 쿼리는"없다 :

    준비된 문을 사용하여, "SQL 쿼리는"없다 :

    그러나 실제 실제 SQL 쿼리에는 재 건설이 없습니다 - 어느 자바 측 않으며, 데이터베이스 측에서.

    그래서, 준비된 명령문의 SQL을 얻을 수있는 방법이 없습니다 - 이러한 SQL 없기 때문에.

    디버깅 목적을 위해, 솔루션 중 하나를 할 수 있습니다 :

  2. ==============================

    2.이 곳은 JDBC API 계약에 정의되어 있지,하지만 당신이 운이 좋다면, 문제의 JDBC 드라이버는 PreparedStatement의 # toString ()를 호출하여 전체 SQL을 반환 할 수 있습니다. 즉

    이 곳은 JDBC API 계약에 정의되어 있지,하지만 당신이 운이 좋다면, 문제의 JDBC 드라이버는 PreparedStatement의 # toString ()를 호출하여 전체 SQL을 반환 할 수 있습니다. 즉

    System.out.println(preparedStatement);
    

    적어도 MySQL의 5.x 및 PostgreSQL을 8.x의 JDBC 드라이버에서이를 지원합니다. 그러나, 대부분의 다른 JDBC 드라이버를 지원하지 않습니다. 당신은 그런 일이 있다면, 가장 좋은 건 Log4jdbc 또는 P6Spy로를 사용하고 있습니다.

    또한, 당신은 또한 연결, SQL 문자열과 문 값을 사용하여 SQL 문자열과 값을 기록 후 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의은 장식 방법에 대한 autogenerators을 제공 대부분의 이클립스는 않습니다). 마지막으로 단지 대신 사용하십시오. 즉 P6Spy로와 배우자들 이미 후드에서 할 기본적으로 어떤이기도합니다.

  3. ==============================

    3.나는, MySQL의 커넥터 v와 JDBC 드라이버. 5.1.31 자바 8을 사용하고 있습니다.

    나는, MySQL의 커넥터 v와 JDBC 드라이버. 5.1.31 자바 8을 사용하고 있습니다.

    나는이 방법을 사용하여 실제 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());
    

    그래서 다음과 같이 떨어지게을 반환합니다 :

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

    4.당신은 쿼리를 실행하고 결과 집합 (당신이 적어도,이 시나리오에) 당신은 단순히과 같이의 ResultSet의 getStatement ()를 호출 할 수 있습니다 기대하는 경우 :

    당신은 쿼리를 실행하고 결과 집합 (당신이 적어도,이 시나리오에) 당신은 단순히과 같이의 ResultSet의 getStatement ()를 호출 할 수 있습니다 기대하는 경우 :

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

    변수의 executedQuery는 결과 집합을 만드는 데 사용 된 문이 포함됩니다.

    지금, 나는이 질문은 꽤 오래 실현,하지만 난이 사람을 도움이되기를 바랍니다 ..

  5. ==============================

    5.나는 () 같은 문자열을 반환 내 경우의 된 toString preparedStatement.toString ()를 사용하여 PreparedStatement로에서 나의 SQL을 추출했습니다

    나는 () 같은 문자열을 반환 내 경우의 된 toString preparedStatement.toString ()를 사용하여 PreparedStatement로에서 나의 SQL을 추출했습니다

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

    지금은 쿼리 값을 모두 추출하고지도로 넣어 정규식을 사용하는 방법 (자바 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());
    

    당신의 preparedStatement.toString이 () 내 경우에는 다른 경우 그냥 "조정"정규식의 문제이다.

  6. ==============================

    6.나는의 prepareStatement에서 SQL을 인쇄하기 위해 다음과 같은 코드를 구현

    나는의 prepareStatement에서 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[" +  "] ...");
                }
    
        }
    
  7. ==============================

    7.아주 늦게 :)하지만 당신은 OraclePreparedStatementWrapper에서 원래 SQL에 의해 얻을 수 있습니다

    아주 늦게 :)하지만 당신은 OraclePreparedStatementWrapper에서 원래 SQL에 의해 얻을 수 있습니다

    ((OraclePreparedStatementWrapper) preparedStatement).getOriginalSql();
    
  8. ==============================

    8.공식 자바 드라이버 42.2.4와 PostgreSQL의 9.6.x를 사용 :

    공식 자바 드라이버 42.2.4와 PostgreSQL의 9.6.x를 사용 :

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

    와 SQL을 보여 것인가? 이미 내가 찾던 인 대체했다. 그냥 포스트 그레스 케이스를 커버하는이 대답을했다.

    나는 간단 있도록 할 수 있다고 생각하지 않았을 것이다.

  9. ==============================

    9.당신이 MySQL을 사용하는 경우 당신은 MySQL의 쿼리 로그를 사용하여 쿼리를 로그인 할 수 있습니다. 다른 공급 업체가이 기능을 제공하는 경우는 모르겠지만, 기회는 그들이 할 수 있습니다.

    당신이 MySQL을 사용하는 경우 당신은 MySQL의 쿼리 로그를 사용하여 쿼리를 로그인 할 수 있습니다. 다른 공급 업체가이 기능을 제공하는 경우는 모르겠지만, 기회는 그들이 할 수 있습니다.

  10. ==============================

    10.코드 조각은 인수 목록에서 SQL PreparedStaments을 변환합니다. 그것은 나를 위해 작동

    코드 조각은 인수 목록에서 SQL PreparedStaments을 변환합니다. 그것은 나를 위해 작동

      /**
             * 
             * 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;
            }
    
  11. ==============================

    11.간단히 기능 :

    간단히 기능 :

    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;
    }
    

    이 PreparedStatement의 벌금 aswell이다.

  12. ==============================

    12.나는 오라클 11g를 사용하고 있는데 PreparedStatement의에서 최종 SQL을 얻을 관리 할 수 ​​있습니다. @Pascal MARTIN 답변을 읽은 후 그 이유를 이해합니다.

    나는 오라클 11g를 사용하고 있는데 PreparedStatement의에서 최종 SQL을 얻을 관리 할 수 ​​있습니다. @Pascal MARTIN 답변을 읽은 후 그 이유를 이해합니다.

    난 그냥 된 PreparedStatement를 사용하는 아이디어를 포기하고 내 요구를 장착 간단한 텍스트 포맷을 사용했다. 여기 내 예입니다 :

    //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);
    

    난 그냥 SQL 쿼리에 대한 문자열 템플릿 포맷 장치로 사용하기 위해 MessageFormat의 클래스를 사용하여 지점에 도착하는 것이 보통 간단하게 루프 당신은 (동안, 경우) sqlInParam가 동적으로 구축 할 수 알아낼.

  13. ==============================

    13.이렇게하려면 당신은 JDBC 연결 및 / 또는 지원하는 낮은 수준에서 SQL 로깅 것을 드라이버가 필요합니다.

    이렇게하려면 당신은 JDBC 연결 및 / 또는 지원하는 낮은 수준에서 SQL 로깅 것을 드라이버가 필요합니다.

    log4jdbc를 살펴 보자

  14. from https://stackoverflow.com/questions/2382532/how-can-i-get-the-sql-of-a-preparedstatement by cc-by-sa and MIT license