Java

Statement와 PreparedStatement

변위니 2025. 1. 7. 16:21

Statement와 PreparedStatement

Statement와 PreparedStatement는 둘 다 JDBC API 에서 제공하는 인터페이스이다.

데이터베이스에서 쿼리를 실행할 때 쿼리를 효율적으로 실행하기 위해서 쿼리 캐싱을 시행한다.

 

쿼리 캐싱

  1. 쿼리를 파싱하고
  2. 최적의 실행계획을 세운 뒤
  3. 실행하는 과정

 

Statement는 쿼리를 실행할 때마다 매번 쿼리를 파싱하고 실행계획을 세우는 과정을 반복한다.

PreparedStatement는 한 번 쿼리가 실행된 후에는 실행계획을 따로 세우지 않고 이전의 실행계획에 파라미터만 변경하여 쿼리를 날린다.
따라서 처음 실행된 실행계획을 재사용하기 때문에 성능 측면에서 좋다.

 

보안 측면에서는 Statement는 입력값을 실제 쿼리에 문자열의 형태로 이어 붙이다. 만약 패스워드를 검색하는 쿼리가 있다고 가정을 했을 때, 유저가 패스워드 값을 입력한 후 이어서 세미콜론을 붙이고 따라서 SQL injection 문제가 발생할 위험이 있다.

 

PreparedStatement는 입력값을 파라미터로 넘긴다. 파라미터로 넘어가는 부분을 ? 로 표시하여 바인딩해서 처리한다.
PreparedStatement를 사용할 때 ?(플레이스 홀)를 사용하면, 사용자 입력값이 쿼리에 직접 삽입되지 않고 JDBC 드라이버가 자동으로 매개변수 값을 이스케이프 처리한다.

 

위와 같은 방식(“; select * from User;”)으로 값을 넘기게 되면 SQL injection을 했을 때 문법 에러가 발생한다.
이렇게 쿼리와 입력 값을 분리해서 처리하기 때문에 입력값은 쿼리의 데이터로만 사용되며 쿼리 구문으로 해석되지 않는다.

 

따라서 SQL 인젝션 공격을 방지하는 데 매우 효과적이다.

 

 

 

 

 


 

PreparedStatement를 사용 시 주의사항

PreparedStatement 는 AutoCloseable를 확장하고 있기 때문에, 사용 후 자원을 해제해 주어야 한다.
또한 실행 전에 컴파일되기 때문에 sql 문법 오류가 있는 경우 컴파일 시점에 예외가 발생한다.



PreparedStatement를 사용 시 발생할 수 있는 성능 이슈

캐싱을 이용하기 때문에 동일한 쿼리를 여러 번 실행할 때 성능을 최적화할 수 있다.

 

하지만 Mysql의 경우, 쿼리는 정상적으로 오류없이 동작 하지만 내부적으로 캐싱하는 동작을 하지않는다.
따라서 캐싱을 하기위해서는 useServerPrepStmtscachePrepStmts 옵션을 설정해야 캐싱을 활용할 수 있다.

 

또한 매개변수 바인딩시 적절한 데이터 타입(setString, setInt)을 사용하여 성능을 최적화할 수 있으며,
대랑의 데이터 처리시 addBatch 와 executeBatch 메서드를 사용하여 배치 처리함으로써 성능을 높일 수 있다.

동일한 Sql 템플릿을 재사용하기 때문에 컴파일 비용을 줄이고 성능을 최적화한다.



SQL Injection 공격을 예방하는 방법

SQL injection 공격을 막기 위해서는 매개변수를 이용해 쿼리에 값을 넣어야 한다.
PreparedStatement를 사용하면 드라이버가 자동으로 매개변수 값을 이스케이프 처리하여 SQL Injection 공격을 방지한다.



PreparedStatement에서 Batch 처리를 사용하는 경우 장점과 주의할 점

Batch의 장점은 대량의 데이터를 한 번에 처리할 수 있기 때문에, 네트워크 비용을 줄이고 연산 횟수를 감소시켜 성능을 향상 시킬 수 있다. 그리고 여러 SQL문을 하나의 트랜잭션으로 묶어서 실행하기 때문에 데이터의 일관성이 유지된다.

 

하지만, 대량의 데이터를 처리하기 때문에 메모리 부족 현상이 발생할 수 있어, 적절한 배치 크기를 설정해야 한다.
executeBatch() 는 쿼리의 실행 결과를 반환하지 않기 때문에 각 쿼리의 행 수 등의 정보를 확인하려면 추가적인 처리가 필요하다.

 



'Java' 카테고리의 다른 글

SQL Injection  (0) 2025.01.07
HashMap의 구조  (0) 2025.01.07
try-catch와 try-with-resources  (0) 2025.01.07
static  (0) 2025.01.07
ArrayList와 LinkedList  (0) 2025.01.07