개발기본지식

[Mybatis] MyBatis에서 샾(#{})과 달러(${})의 차이

개발하는소유밍 2024. 2. 16. 16:06

회사 입사했을때부터 당연스럽게 써왔던 #{}

다른 방법도 있을거라고 생각도 못했는데 최근 알아버린 사실이 있었으니..

 

마이바티스(MyBatis)를 사용하는 프로젝트에서 mapper 쿼리문이 담긴 XML 파일을 보면

 XML에 쿼리문을 작성할 때 파라미터 값을 설정하게 될텐데 이때 ${}과 #{}를 사용하게 된다.

이 둘은 용도가 다르므로 명확하게 구분하여 사용 해야 한다!  (보안을 고려한다면 #{}를 사용)

 

  #{ } ${ }
1   파싱된 쿼리문이 재활용(캐싱)되기 때문에 효율적    (성능상의 단점) 값이 넣어진 채로 쿼리문이 수행되기 때문에
  파라미터의 값이 바뀔 때마다 항상 쿼리문 파싱을 진행
2   *SQL Injection을 방어(*PreparedStatement 방식으로 수행)   *SQL Injection에 취약
3   변수에 작은 따옴표(‘)가 자동으로 붙여져서
  쿼리가 수행되기 때문에 table_1, table_2 에 대해
  table_#{tableId}  같은 식으로 쿼리문을 작성할 수 없음

  →  SQLSyntaxErrorException 오류 발생
  작은 따옴표(‘)가 붙지 않기 때문에 *아래 예시처럼
  테이블 이름이나 컬럼 이름을 동적으로 결정할 때 사용할수 있음

 


(1) * SQL Injection (SQL 삽입공격) 이란?

 

SELECT * FROM Users WHERE id = '${id}' AND password = '${password}'
SELECT * FROM Users WHERE id = '${id}' 'OR 1=1 -- AND password = '${password}'

 

 - 위와 같은 쿼리문을 실행할 때, 악의적인 사용자가 SQL 구문('OR 1=1 --)을 주입하게 되면 where절에 있는 싱글쿼터를 닫아주기 위한 싱글쿼터(')와 추가 조건 (OR 1=1), 그리고 패스워드 조건 절은 주석(--)처리 해줌으로 비밀번호 없이 로그인이 가능해진다.

 


(2) * PreparedStatement 이란?

 - 데이터베이스 관리 시스템(DBMS)에서 동일하거나 비슷한 데이터베이스 문을 높은 효율성으로 반복적으로 실행하기 위해 사용되는 기능을 말한다.

 


(3) * 예시

 

-- 1
SELECT name, email FROM User WHERE id = #{id}

-- 2
SELECT name FROM user_#{tableId} WHERE id = #{id}

-- 3
SELECT name, email FROM User WHERE Id = ${id}

 

 - 1. 쿼리문을 작성할 때 #{ }을 사용하는 경우, WHERE id = ? 파라미터가 바인딩되어 수행되며,

 변수에 작은 따옴표(‘)가 자동으로 붙여 쿼리가 수행되기 때문에 '#{id}'와 같은 식으로 쿼리문을 작성하지 않아도 된다.

 

 -  2. 테이블 설계가 user_1, user_2과 같이 분리되어 구성되어 있을 때에는 user_#{tableId}로 작성할 수 없다.

  위 쿼리문이 수행되면 tableId 변수 양쪽에 따옴표가 붙기 때문에 SQLSyntaxErrorException 오류가 발생한다.

 

 -  3. ${ }#{}을 사용한 것과 다르게  값이 넣어진 채로 쿼리문이 수행되며,

  그렇기 때문에 파라미터의 값이 바뀔 때마다 항상 쿼리문 파싱을 진행해야 한다.
  작은 따옴표(‘)가 붙지 않기 때문에 -- 2 의 예시처럼 테이블 이름이나 컬럼 이름을 동적으로 결정할 때 사용할 수 있다.

300x250