ye._.veloper

[ D B ] Mybatis ${}와 #{}의 차이 본문

D B

[ D B ] Mybatis ${}와 #{}의 차이

ye._.veloper 2023. 1. 24. 23:13

Mybatis에서 XML파일에 쿼리를 작성하다 문득 ${ }#{ }로 파라미터를 가져오는 차이점이 궁금해져서 알아봤다.

 

 

아래는 ${ }와 #{ }의 차이를 알아보기 위해 작성한 예시이다.

(아래 예시는 아이디의 수(count)를 구해 같은 아이디가 있는지 중복 검사를 하는 쿼리이다.)

<select id="idCheck" parameterType="userDto" resultType="int">
    SELECT COUNT(*) 
    FROM user
    WHERE user_id = ____________
</select>

밑줄 친 부분에 #{ }, ${ }가 들어갈 두 가지의 경우의 과정과 장,단점을 비교해보자

 

☁ #{  }

<select id="idCheck" parameterType="userDto" resultType="int">
    SELECT COUNT(*) 
    FROM user
    WHERE user_id = #{user_id}
</select>

# : PreparedStatement를 의미

 

◽ 사용 과정

   1 ) PreparedStatement 생성

   2 ) PreparedStatement parameter 값 안전하게 생성

   3 ) PreparedStatement가 제공하는 Set 계열의 method를 사용하여 ?(물음표)를 대체할 값을 지정

   4 ) 전달해 온 parameter를 String으로 인식 ➡ 자동으로 따옴표(Quotation)가 붙음

 

◽ 사용 이유

 · 안전하고 빠르기 때문에 사용 권장

 ⚡ 빠른 이유

    - Prepared(준비)

      위에서 언급한 "준비"는 컴파일(Parsing)을 의미하며, 컴파일이 미리 되어있기 때문에 Statement에 비해 성능에 이점이 있다.

 

◽ 특징

 · 파라미터가 String 형태로 들어가 자동으로 따옴표(Quotation)가 붙는다.

         WHERE user_id = 'user1'

 

· 쿼리 주입을 예방할 수 있어 보안 문제(SQL Injection)에서 유리하다.

 

MyBatis에서 위와 같은 #{}이 사용된 쿼리문이 실행되면 아래와 같이 쿼리문에 ?(물음표)가 생기며 파싱된다.

<select id="idCheck" parameterType="userDto" resultType="int">
    SELECT COUNT(*) 
    FROM user
    WHERE user_id = ?
</select>

 · #{}을 사용하는 경우, PreparedStatement를 생성하게 되는데 위 ?(물음표)에 파라미터가 바인딩되어 수행된다.

    이렇게 파싱된 쿼리문은 재활용(캐싱)되기 때문에 효율적이다.

        ➡ #{ }에 담긴 parameter 값이 달라져도 같은 쿼리로 인식하여 속도가 빠르다.

 

 · 변수에 작은 따옴표(‘)가 자동으로 붙기 때문에 '#{user_id}' 이런 식으로 직접 따옴표를 붙이지 않아도 된다.

 · #{ }를 사용하는 경우는 사용자의 입력을 받는 경우 또는 데이터가 많은 경우에 사용한다.

 

☁ ${  }

<select id="idCheck" parameterType="userDto" resultType="int">
    SELECT COUNT(*) 
    FROM user
    WHERE user_id = ${user_id}
</select>

 

◽ 사용 과정

   1 ) Statement 생성

   2 ) Statement의 parameter 값을 그대로 전달

   3 ) parameter를 그대로 전달하기 때문에 문자열에 따옴표(Quotation)가 붙지 않음

 

◽ 특징

 · { } 안의 파라미터 값 그대로 쿼리문이 수행된다.

        ➡ WHERE user_id = user1

 

 · 파라미터 값이 넣어진 상태로 쿼리문이 수행되기 때문에 파라미터의 값이 바뀔 때마다 항상 쿼리문에 대한 파싱을 진행해야 한다.

        ➡ ${ }에 담긴 parameter 값이 달라지면 다른 쿼리로 인식하기 때문에 새로 파싱 작업을 해줘야 함

        ➡ 속도가 저하될 수 있다. (성능상 단점)

 

 · 쿼리 주입을 예방할 수 없어 보안 문제(SQL Injection)에서 불리하다.

        ➡ 자주 바뀌거나 사용자의 입력을 받아 쿼리로 전달하는 경우에는 ${ }을 사용하지 않는 것이 좋다.

        ➡ ORDER BY 사용 시, 따옴표가 붙지 않는 것이 좋으니 ${ }를 사용

 

 · 예를 들어, ${ }를 사용하는 경우는 아래와 같이 테이블명, 컬럼명을 동적으로 결정할 때 사용할 수 있다.

<select id="idCheck" parameterType="userDto" resultType="int">
    SELECT COUNT(*) 
    FROM user_${id}
    WHERE user_id = #{user_id}
</select>

 

- SQLInjection 따로 글 올리기

 

Ref.

Mybatis에서 샾(#{})과 달러(${})의 차이는 무엇일까?

Mybatis에서 #{}와 ${}의 차이

[MyBatis] #{} 와 ${} 개념과 차이점

<Mybatis> #과 $의 차이를 알아보자!

Comments