PreparedStatement의 SQL을 어떻게 얻을 수 있습니까?
다음과 같은 메소드 서명이있는 일반적인 Java 메소드가 있습니다.
private static ResultSet runSQLResultSet(String sql, Object... queryParams)
연결을 열고 PreparedStatement
sql 문을 사용하여 변수를 작성하고 queryParams
변수 길이 배열 의 매개 변수를 실행하고 실행하고 ResultSet
(a CachedRowSetImpl
)를 캐시 하고 연결을 닫은 후 캐시 된 결과 세트를 리턴합니다.
오류를 기록하는 방법에 예외 처리가 있습니다. 디버깅에 매우 도움이되므로 SQL 문을 로그의 일부로 기록합니다. 내 문제는 String 변수를 sql
로깅하면 템플릿 값을 실제 값 대신?로 기록한다는 것입니다. 실행 된 실제 명령문 을 기록하고 싶습니다 .
그래서 ...에 의해 실행될 실제 SQL 문을 얻는 방법이 PreparedStatement
있습니까? ( 내가 직접 구축 하지 않고 . PreparedStatement's
SQL 에 액세스하는 방법을 찾을 수 없다면 아마도 내 자신 의 SQL에서 직접 구축하게 될 것입니다 catch
.)
준비된 명령문을 사용하면 "SQL 쿼리"가 없습니다.
- 자리 표시자가 포함 된 명세서가 있습니다.
- DB 서버로 전송
- 그리고 거기에서 준비
- 이는 SQL 문이 "분석 됨", 구문 분석 됨,이를 나타내는 일부 데이터 구조가 메모리에서 준비됨을 의미합니다.
- 그런 다음 변수를 바인딩했습니다.
- 서버로 전송
- 준비된 문장이 실행됩니다.
그러나 실제 실제 SQL 쿼리의 재구성은 없습니다. Java 측이나 데이터베이스 측이 아닙니다.
따라서 준비된 명령문의 SQL을 얻을 수있는 방법은 없습니다. 그러한 SQL이 없기 때문입니다.
디버깅 목적으로 솔루션은 다음 중 하나입니다.
- 자리 표시 자와 데이터 목록이 포함 된 명세서의 코드를 출력합니다.
- 또는 "손으로"일부 SQL 쿼리를 "빌드"합니다.
JDBC API 계약에는 정의되어 있지 않지만 운이 좋으면 문제가되는 JDBC 드라이버는을 호출하여 전체 SQL을 반환 할 수 있습니다 PreparedStatement#toString()
. 즉
System.out.println(preparedStatement);
적어도 MySQL 5.x 및 PostgreSQL 8.x JDBC 드라이버가이를 지원합니다. 그러나 대부분의 다른 JDBC 드라이버는이를 지원하지 않습니다. 그러한 것이 있다면 가장 좋은 방법은 Log4jdbc 또는 P6Spy를 사용하는 것 입니다.
또는, Connection
SQL 문자열 및 명령문 값을 사용하고 PreparedStatement
SQL 문자열 및 값을 로깅 한 후를 리턴하는 일반 함수를 작성할 수도 있습니다. 킥오프 예 :
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
을 랩 (장식)하고 모든 메소드를 재정 의하여 사용자가 실제 메소드를 호출하고 모든 메소드 의 값을 수집하고 다음 중 하나 일 때마다 "실제"SQL 문자열을 느리게 구성 하는 사용자 정의를 구현하는 것입니다. 방법 (아주 작동하지만 대부분의 IDE의는 이클립스가하는 장식 방법에 대한 autogenerators을 제공합니다)라고합니다. 마지막으로 대신 사용하십시오. 그것은 기본적으로 P6Spy와 컨소시엄이 이미 후드에서 수행하는 것입니다. PreparedStatement
PreparedStatement
setXXX()
executeXXX()
MySQL 커넥터 v. 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
.
이제이 질문이 상당히 오래되었다는 것을 알고 있지만 이것이 누군가에게 도움이되기를 바랍니다.
readyStatement.toString ()을 사용하여 PreparedStatement에서 SQL을 추출했습니다. 제 경우에는 toString ()이 다음과 같이 String을 반환합니다.
org.hsqldb.jdbc.JDBCPreparedStatement@7098b907[sql=[INSERT INTO
TABLE_NAME(COLUMN_NAME, COLUMN_NAME, COLUMN_NAME) VALUES(?, ?, ?)],
parameters=[[value], [value], [value]]]
이제 정규식을 사용하여 쿼리와 값을 추출하고 맵에 넣는 메소드 (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());
If your preparedStatement.toString() is different than in my case it's just a matter of "adjusting" regex.
Very late :) but you can get the original SQL from an OraclePreparedStatementWrapper by
((OraclePreparedStatementWrapper) preparedStatement).getOriginalSql();
Using PostgreSQL 9.6.x with official Java driver 42.2.4
:
...myPreparedStatement.execute...
myPreparedStatement.toString()
Will show the SQL with the ? already replaced, which is what I was looking for. Just added this answer to cover the postgres case.
I would never have thought it could be so simple.
If you're using MySQL you can log the queries using MySQL's query log. I don't know if other vendors provide this feature, but chances are they do.
I implemented the following code for printing SQL from PrepareStatement
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[" + "] ...");
}
}
Code Snippet to convert SQL PreparedStaments with the list of arguments. It works for me
/**
*
* 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;
}
Simply function:
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;
}
It's fine aswell for preparedStatement.
I'm using Oralce 11g and couldn't manage to get the final SQL from the PreparedStatement. After reading @Pascal MARTIN answer I understand why.
I just abandonned the idea of using PreparedStatement and used a simple text formatter which fitted my needs. Here's my example:
//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);
You figure out the sqlInParam can be built dynamically in a (for,while) loop I just made it plain simple to get to the point of using the MessageFormat class to serve as a string template formater for the SQL query.
To do this you need a JDBC Connection and/or driver that supports logging the sql at a low level.
Take a look at log4jdbc
참고URL : https://stackoverflow.com/questions/2382532/how-can-i-get-the-sql-of-a-preparedstatement
'IT story' 카테고리의 다른 글
XHTML에서 중첩 된 스팬 태그가 정상입니까? (0) | 2020.06.14 |
---|---|
catch 및 finally 절에서 예외가 발생했습니다. (0) | 2020.06.14 |
Node.js에서 파일 읽기 (0) | 2020.06.14 |
문자열 형식의 명명 된 자리 표시 자 (0) | 2020.06.14 |
로컬에서 실행되는 웹 페이지에서 로컬 파일에 대한 링크를 만들려면 어떻게해야합니까? (0) | 2020.06.14 |