Mybatis #(샵)과 $(달러)의 차이
[Desc]
MyBatis에서 변수 #과 $의 차이를 잘모르고 사용하는 것 같아 정리했습니다.
SELECT * FROM TEST WHERE 1=1 AND TEST_ID = #{testId}
위와 같은 쿼리문을 수행하게 되면 database에서는 아래 쿼리문에 대한 의미, 구문분석 및 파싱을 진행하게 됩니다.
(오라클의 PreparedStatements)
//(오라클에서 파싱되어 받는쿼리) P1 SELECT * FROM TEST WHERE 1=1 AND TEST_ID = ?
만약 testId에 1값이 바인드 되게 되면 database에서는 이미 파싱되어 있는 쿼리문(P1)을 재활용하게 됩니다.
testId 2값이 들어오면 P1에 파싱되어있는 쿼리문을 재활용을 합니다.
단 데이터베이스 옵티마이저에 대한 수행 계획은 항상 동일하다는게 단점입니다.
수행 계획에 따른 데이터 추출은 데이터의 분포도에 영향을 받게 되는데
만약 [1]이라는 값이 TEST테이블에 4개가 존재하고 [2]라는 값이 1000개 존재한다고 한다면
1을 추출할때는 인덱스 스캔이 유리하고
2를 추출할때는 풀스캔이 유리합니다.
즉 위의 쿼리문을 파싱 할때 TEST_ID컬럼에 인덱스가 있다면 무조건 인덱스 스캔을 수행 계획으로 수립하게 되므로
2값이 들어올때에도 인덱스 스캔으로 인한 성능 저하가 발생할 수 있습니다.
하지만 #을 사용할때는 SQL Injection 대비가 가능
쿼리문을 실행하기에 앞서 구문분석, 의미 분석, 파싱 작업을 진행하기에 SQL Injection의 코드를 만나게 되면 오류를 발생 시킵니다.
그럼 아래와 같은 쿼리는 어떨까요?
SELECT * FROM TEST WHERE 1=1 AND TEST_ID = ${testId}${testId} 가 1 일때는 아래와 같은 쿼리문이 실행되며 데이터베이스에서는 의미,구문 분석 및 파싱 작업을 진행합니다.(Statements)
//오라클에서 받는쿼리 SELECT * FROM TEST WHERE 1=1 AND TEST_ID = 1여기서 유념해야하는 부분은 #을 사용할때는 ?로 치환되고 $사용할때는 1이라는 상수로 치환이 되어 수행됩니다. ${testId} 값이 변경되면 2,3,4,5... 과 같이 값이 변경 될 때마다 파싱 작업을 항상 진행하여 성능상의 단점이 존재합니다.
SELECT * FROM TEST WHERE 1=1 AND TEST_ID = ${testId} AND PASSWORD = ${passWd} //Sqlinjection 공격 SELECT * FROM TEST WHERE 1=1 AND TEST_ID = ${testId} --AND PASSWORD = ${passWd}또한 SQL Injection 공격에 취약할 수 있습니다.
그렇기 때문에 중요한 쿼리에서는 $를 사용하지않고 #을 사용합니다. 단 $를 사용할 때는
ORDER BY ${columnName} DESC or SELECT ${columnName} FROM tableName
'Framework & ORM > 운영&개발Tip' 카테고리의 다른 글
Console(Log) 쿼리를 아름답게 찍기 (3) | 2018.01.11 |
---|---|
Lombok 설치 및 사용법 (1) | 2018.01.11 |
Mybatis Insert후 return Key (0) | 2018.01.11 |
Spring 4.x 이상일때 iBatis와 MyBatis 동시 사용하기 (2) | 2018.01.11 |
대용량 Insert, Update시 Batch처리 주의점 및 방법(Mybatis, Ibatis) (0) | 2018.01.11 |