MyBatis 를 사용할 때 데이터를 사용하는 대입과 치환 방법 2가지가 있다.
#{} 방법
//Model
public class VOModel {
String name;
...getter, setter 생략
}
<mapper namespace="mapper">
<select id="selectId" parameterType="VOModel">
SELECT * FROM test_table WHERE name = #{name}
</select>
</mapper>
위와 같이 #{name} 을 사용하게 되면 아래와 같이 치환된다. name 의 값이 abc 라고 하면 아래와 같다.
SELECT * FROM test_table WHERE name = 'abc'
#{} 으로 사용하게 되면 변수에 작은 따옴표(')가 자동으로 붙여 쿼리가 수행되기 때문에 작은따옴표를 따로
붙일 필요가 없다.
좀더 깊이 들어가자면 #{} 를 사용하게 되면 처음 쿼리는 아래와 같다.
<mapper namespace="mapper">
<select id="selectId" parameterType="VOModel">
SELECT * FROM test_table WHERE name = ?
</select>
</mapper>
#{name} 자리에는 쿼리문을 수행하는 preparedStatement 가 생성되어 물음표(?)를 넣어 파싱하게 되고
컴파일 후 실행할 때 값을 바인딩 하고 쿼리문이 수행된다. 이때 ? 자리에는 값을 바인딩하는데
작은 따옴표('')가 자동으로 붙어 바인딩 된다.
이러한 역할로 인해 SQL Injection 공격을 예방할 수 있다.
또한 PreparedStatement 객체는 SQL 쿼리문을 파싱하는 과정을 캐시에 담아놓고 사용하기 때문에
반복적인 쿼리문을 사용할 때 효율적이다.
${} 방법
<mapper namespace="mapper">
<select id="selectId" parameterType="VOModel">
SELECT * FROM test_table WHERE name = ${name}
</select>
</mapper>
Statement 방식인 ${name} 과 같이 사용하게 되면 ${name} 자리에 값이 바인딩된 채로 쿼리문을 수행하게 된다.
그래서 매번 값이 바뀔때마다 새로운 쿼리문으로 받아들여 SQL 쿼리문을 파싱해야 하기 때문에
성능상 좋지 않다.
SELECT * FROM test_table WHERE name = abc
또한 작은따옴표(')를 자동으로 붙여주지 않아 SQL Injection 공격에 취약하다.
하지만 아에 사용 안하는건 아니다.
동적으로 테이블명이 바껴야할때 사용하기도 한다.
#{} 를 테이블명에 사용하게되면 작은따옴표(')가 자동으로 붙어 에러가 나기 때문에 ${} 대입방법을 사용한다.