-
MyBatis - ${}와 #{}의 차이Database/MyBatis 2022. 3. 22. 12:39
검색 유형에 따른 코드의 구성
#{}를 사용한 기존 코드
<choose> <when test="'INDX_SEQ'.equals(searchType)"> SELECT <include refid="dataColumns"/> FROM TBL_XBR_IDX_CALC WHERE INDX_SEQ LIKE '%' || #{searchKeyword} || '%' ORDER BY INDX_SEQ, CACL_ORD </when> <when test="'INDX_NM'.equals(searchType)"> SELECT <include refid="dataColumns"/> FROM TBL_XBR_IDX_CALC WHERE INDX_NM LIKE '%' || #{searchKeyword} || '%' ORDER BY INDX_SEQ, CACL_ORD </when> <when test="'CACL_ORD'.equals(searchType)"> SELECT <include refid="dataColumns"/> FROM TBL_XBR_IDX_CALC WHERE CACL_ORD LIKE '%' || #{searchKeyword} || '%' ORDER BY INDX_SEQ, CACL_ORD </when> <when test="'TRGT_ELMT_ID'.equals(searchType)"> SELECT <include refid="dataColumns"/> FROM TBL_XBR_IDX_CALC WHERE TRGT_ELMT_ID LIKE '%' || #{searchKeyword} || '%' ORDER BY INDX_SEQ, CACL_ORD </when> <when test="'TRGT_ELMT_LABEL'.equals(searchType)"> SELECT <include refid="dataColumns"/> FROM TBL_XBR_IDX_CALC WHERE TRGT_ELMT_LABEL LIKE '%' || #{searchKeyword} || '%' ORDER BY INDX_SEQ, CACL_ORD </when> <when test="'INDX_CALC_BASE_DT'.equals(searchType)"> SELECT <include refid="dataColumns"/> FROM TBL_XBR_IDX_CALC WHERE INDX_CALC_BASE_DT LIKE '%' || #{searchKeyword} || '%' ORDER BY INDX_SEQ, CACL_ORD </when> <when test="'OPRTR'.equals(searchType)"> SELECT <include refid="dataColumns"/> FROM TBL_XBR_IDX_CALC WHERE OPRTR LIKE '%' || #{searchKeyword} || '%' ORDER BY INDX_SEQ, CACL_ORD </when> <when test="'FNCTN'.equals(searchType)"> SELECT <include refid="dataColumns"/> FROM TBL_XBR_IDX_CALC WHERE FNCTN LIKE '%' || #{searchKeyword} || '%' ORDER BY INDX_SEQ, CACL_ORD </when> <when test="'USE_TXN_IND_CD'.equals(searchType)"> SELECT <include refid="dataColumns"/> FROM TBL_XBR_IDX_CALC WHERE USE_TXN_IND_CD LIKE '%' || #{searchKeyword} || '%' ORDER BY INDX_SEQ, CACL_ORD </when> <when test="'RGS_DTTM'.equals(searchType)"> SELECT <include refid="dataColumns"/> FROM TBL_XBR_IDX_CALC WHERE RGS_DTTM LIKE '%' || #{searchKeyword} || '%' ORDER BY INDX_SEQ, CACL_ORD </when> </choose>
사용자로부터 검색 유형(searchType)과 검색 키워드(searchKeyword)를 입력받아 조건에 맞는 데이터를 조회하기 위한 코드이다. 코드를 보면 알겠지만, 검색 유형(searchType) 조건에 따라 중복된 코드가 작성된 것을 확인할 수 있다. 중복된 코드를 제거하고 코드를 간결하게 구성하기 위해 아래와 같이 코드를 작성하였다.
${}를 사용한 변경된 코드
SELECT <include refid="dataColumns"/> FROM TBL_XBR_IDX_CALC WHERE ${searchType} LIKE '%' || #{searchKeyword} || '%' ORDER BY INDX_SEQ, CACL_ORD
검색 유형(searchType)을 #{}이 아닌 ${}으로 입력받아 코드를 구성하였다. 앞선 #{}를 사용한 코드와 비교해 보았을 때, 코드의 중복을 줄이고 훨씬 간결하게 구성하였음을 확인할 수 있다. 그렇다면, MyBatis의 #{}과 ${}의 차이점을 알아보도록 하겠다.
MyBatis의 ${}와 #{}의 차이
#{}의 사용
<select id="selectName" parameter="String" returnData="HashMap"> SELECT name FROM user WHERE id = #{id} </select>
우선, 위와 같은 코드를 #{}을 사용하여 작성한다.
SELECT name FROM user WHERE id = ?
MyBatis에서는 #{}이 사용된 쿼리문이 실행되면 위와 같이 쿼리문에 ?가 생기며 파싱 된다. 쿼리문을 작성할 때 #{}을 사용하는 경우 PreparedStatement를 생성하게 되는데, 이때 ?에 파라미터가 바인딩되어 수행된다. 이렇게 파싱 된 쿼리문은 재활용(캐싱)되기 때문에 좀 더 효율적으로 사용할 수 있다.
<select id="selectName" parameter="String" returnData="HashMap"> SELECT name FROM user_#{tableId} WHERE id = #{id} </select>
또한, #{}는 변수에 작은따옴표(')가 자동으로 붙여 쿼리문이 수행되기 때문에 위 코드와 같은 식으로 작성할 수 없다. 위 쿼리문이 수행되면 tableId 변수 양쪽에 작은따옴표(')가 붙기 때문에 SQLSyntaxErrorException 오류가 발생한다.
${}의 사용
<select id="selectName" parameter="String" returnData="HashMap"> SELECT name FROM user_${tableId} WHERE id = #{id} </select>
쿼리문에 #{}을 사용한 것과 다르게 ${}을 사용하면 작은따옴표(')가 붙지 않기 때문에 위 코드와 같이 테이블 이름이나 칼럼 이름을 동적으로 결정할 때 사용할 수 있다.
${}을 사용하면 값이 넣어진 채로 쿼리문이 수행된다. 그렇기 때문에 파라미터의 값이 바뀔 때마다 항상 쿼리문 파싱을 진행해야 하기 때문에, 성능상의 단점이 존재한다.
또한, ${}를 사용한 경우 SQL Injection에 취약하다는 단점이 있다.
SQL Injection
SQL Injection이란?
SQL Injection은 응용 프로그램 보안 상의 허점을 의도적으로 이용해 악의적인 SQL 문을 실행되게 함으로써 데이터베이스를 비정상적으로 조작하는 방법이다. MyBatis의 ${}을 사용하면 주로 발생할 수 있는 가장 큰 허점이며, 이를 막기 위해서는 #{}을 사용하는 것을 지향하고 있다.
<select id="selectUser" parameterType="Map" resultType="..."> SELECT * FROM user WHERE id = '${id}' AND password = '${password}' </select>
사용자로부터 아이디와 패스워드를 입력받고 사용자의 정보를 조회할 수 있는 쿼리문이 있다고 가정해보겠다. 만일 id의 파라미터 값으로 admin' --이 입력되는 경우는 어떻게 될까? 실제로 파싱 되는 쿼리문은 아래와 같을 것이다.
SELECT * FROM user WHERE id = 'admin' -- ' AND password = ''
비밀번호에 대한 조건은 -- 주석처리가 되기 때문에 사라지게 되며 id만 입력해도 관리자 계정 정보를 조회할 수 있게 된다. 따라서, ${} 사용하게 되는 경우 #{}을 사용하는 것보다 SQL Injection에 취약하다.
728x90'Database > MyBatis' 카테고리의 다른 글
Myabtis - <sql>, <include> 태그 (0) 2022.04.28 MyBatis - 대소문자 구분 없이 데이터 조회하기 (0) 2022.03.24 MyBatis - <choose>, <when>, <otherwise> 태그 (0) 2022.03.21 MyBatis - MyBatis의 <if> 태그 (0) 2022.03.21 MyBatis - DBMS 별 LIKE 문법 (0) 2022.03.21