MyBatis XML — CDATA, #{}, ${}

2026. 6. 8. 17:36ยท๐Ÿ–ฅ๏ธ development

1. CDATA๋ž€?

<![CDATA[ ]]>๋Š” XML ํŒŒ์„œ๊ฐ€ ๋‚ด๋ถ€ ๋‚ด์šฉ์„ ํŒŒ์‹ฑํ•˜์ง€ ์•Š๊ณ  ์ˆœ์ˆ˜ ๋ฌธ์ž์—ด๋กœ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๊ฐ์‹ธ๋Š” ๊ตฌ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

์™œ ํ•„์š”ํ•œ๊ฐ€?

MyBatis XML ๋งคํผ๋Š” XML ํŒŒ์ผ์ด๊ธฐ ๋•Œ๋ฌธ์—
<, >, & ๊ฐ™์€ ํŠน์ˆ˜๋ฌธ์ž๋Š” XML ํƒœ๊ทธ๋กœ ์˜ค์ธ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<!-- โŒ CDATA ์—†์ด → XML ํŒŒ์‹ฑ ์˜ค๋ฅ˜ -->
<if test="age > 10">
    AND age > 10        <!-- > ๊ฐ€ XML ๋‹ซ๋Š” ํƒœ๊ทธ๋กœ ์˜ค์ธ -->
</if>

<!-- โœ… CDATA ์‚ฌ์šฉ → ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ -->
<if test="age > 10">
    <![CDATA[
        AND age > 10
    ]]>
</if>

 

XML ํŠน์ˆ˜๋ฌธ์ž ๋ชฉ๋ก

ํŠน์ˆ˜๋ฌธ์ž XML ์˜๋ฏธ SQL์—์„œ ์‚ฌ์šฉ ์‹œ
< ํƒœ๊ทธ ์‹œ์ž‘ CDATA ๋˜๋Š” &lt;
> ํƒœ๊ทธ ๋ CDATA ๋˜๋Š” &gt;
& ์—”ํ‹ฐํ‹ฐ ์‹œ์ž‘ CDATA ๋˜๋Š” &amp;
" ์†์„ฑ๊ฐ’ ๊ตฌ๋ถ„ CDATA ๋˜๋Š” &quot;
' ์†์„ฑ๊ฐ’ ๊ตฌ๋ถ„ CDATA ๋˜๋Š” &apos;

 

CDATA ์‚ฌ์šฉ ์˜ˆ์‹œ

<select id="getUserList" resultType="UserDto">
    SELECT *
    FROM users
    <![CDATA[
        WHERE age >= #{minAge}
        AND salary <= #{maxSalary}
        AND created_at > #{startDate}
    ]]>
</select>

 

CDATA ๋ฒ”์œ„ ์ฃผ์˜

CDATA ์•ˆ์—์„œ๋Š” MyBatis ํƒœ๊ทธ(<if>, <where> ๋“ฑ)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
ํŠน์ˆ˜๋ฌธ์ž๊ฐ€ ํฌํ•จ๋œ SQL ๋ถ€๋ถ„๋งŒ CDATA๋กœ ๊ฐ์‹ธ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

<!-- โŒ CDATA ์•ˆ์— MyBatis ํƒœ๊ทธ ์‚ฌ์šฉ ๋ถˆ๊ฐ€ -->
<![CDATA[
    SELECT * FROM users
    <if test="name != null">   ← ์ธ์‹ ์•ˆ ๋จ
        WHERE name = #{name}
    </if>
]]>

<!-- โœ… ํŠน์ˆ˜๋ฌธ์ž๊ฐ€ ์žˆ๋Š” ๋ถ€๋ถ„๋งŒ CDATA๋กœ ๊ฐ์‹ธ๊ธฐ -->
<select id="getUserList" resultType="UserDto">
    SELECT * FROM users
    <where>
        <if test="minAge != null">
            <![CDATA[ AND age >= #{minAge} ]]>
        </if>
        <if test="maxSalary != null">
            <![CDATA[ AND salary <= #{maxSalary} ]]>
        </if>
    </where>
</select>

 


2. #{} — PreparedStatement ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ

#{}๋Š” JDBC์˜ PreparedStatement ๋ฐฉ์‹์œผ๋กœ ๊ฐ’์„ ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค.
๊ฐ’์„ ?๋กœ ์น˜ํ™˜ํ•œ ํ›„ ์•ˆ์ „ํ•˜๊ฒŒ ๋ฐ”์ธ๋”ฉํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

๋™์ž‘ ๋ฐฉ์‹

SELECT * FROM users WHERE name = #{name}
MyBatis ์ฒ˜๋ฆฌ ๊ณผ์ •:
1. SELECT * FROM users WHERE name = ?  (? ๋กœ ์น˜ํ™˜)
2. PreparedStatement.setString(1, "ํ™๊ธธ๋™")  (๊ฐ’ ๋ฐ”์ธ๋”ฉ)
3. ์‹คํ–‰

 

ํŠน์ง•

  • โœ… SQL Injection ๋ฐฉ์–ด
  • โœ… ๋ฌธ์ž์—ด์— ์ž๋™์œผ๋กœ ๋”ฐ์˜ดํ‘œ ์ฒ˜๋ฆฌ
  • โœ… ํƒ€์ž…์— ๋งž๊ฒŒ ์ž๋™ ๋ณ€ํ™˜
  • โœ… ๊ฐ’(VALUE) ๋ฐ”์ธ๋”ฉ์— ์‚ฌ์šฉ

์‚ฌ์šฉ ์˜ˆ์‹œ

<select id="getUser" resultType="UserDto">
    SELECT *
    FROM users
    WHERE user_id = #{userId}
    AND name = #{name}
    AND status = #{status}
</select>
<insert id="insertUser">
    INSERT INTO users (name, email, age)
    VALUES (#{name}, #{email}, #{age})
</insert>
<update id="updateUser">
    UPDATE users
    SET name = #{name},
        email = #{email}
    WHERE user_id = #{userId}
</update>

3. ${} — ๋ฌธ์ž์—ด ์ง์ ‘ ์น˜ํ™˜

${}๋Š” ๊ฐ’์„ ๋ฌธ์ž์—ด๋กœ ๊ทธ๋Œ€๋กœ ์น˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
SQL์— ๊ฐ’์ด ์ง์ ‘ ์‚ฝ์ž…๋˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

 

๋™์ž‘ ๋ฐฉ์‹

SELECT * FROM users WHERE name = '${name}'
MyBatis ์ฒ˜๋ฆฌ ๊ณผ์ •:
1. name = "ํ™๊ธธ๋™" ์ด ๋“ค์–ด์˜ค๋ฉด
2. SELECT * FROM users WHERE name = 'ํ™๊ธธ๋™'  (๊ทธ๋Œ€๋กœ ์‚ฝ์ž…)
3. ์‹คํ–‰

 

ํŠน์ง•

  • โŒ SQL Injection ์œ„ํ—˜
  • โŒ ๋ฌธ์ž์—ด ๋”ฐ์˜ดํ‘œ ์ง์ ‘ ์ฒ˜๋ฆฌ ํ•„์š”
  • โœ… ์ปฌ๋Ÿผ๋ช…, ํ…Œ์ด๋ธ”๋ช…, ์ •๋ ฌ ๋ฐฉํ–ฅ์— ์‚ฌ์šฉ
  • โœ… #{} ๋กœ ๋Œ€์ฒด ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉ

${}๋ฅผ ์จ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

์ปฌ๋Ÿผ๋ช…, ํ…Œ์ด๋ธ”๋ช…, ORDER BY ๋ฐฉํ–ฅ์€ #{} ๋กœ ๋ฐ”์ธ๋”ฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋งŒ ${} ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

<!-- ๋™์  ์ •๋ ฌ -->
<select id="getUserList" resultType="UserDto">
    SELECT *
    FROM users
    ORDER BY ${sortColumn} ${sortDirection}
</select>
<!-- ๋™์  ํ…Œ์ด๋ธ”๋ช… -->
<select id="getDataByYear" resultType="DataDto">
    SELECT *
    FROM ${tableName}
    WHERE year = #{year}
</select>

 


4. #{} vs ${} ํ•ต์‹ฌ ๋น„๊ต

  #{} ${}
์ฒ˜๋ฆฌ ๋ฐฉ์‹ PreparedStatement (? ์น˜ํ™˜) ๋ฌธ์ž์—ด ์ง์ ‘ ์น˜ํ™˜
SQL Injection โœ… ๋ฐฉ์–ด๋จ โŒ ์œ„ํ—˜
๋”ฐ์˜ดํ‘œ ์ฒ˜๋ฆฌ โœ… ์ž๋™ ์ฒ˜๋ฆฌ โŒ ์ง์ ‘ ์ฒ˜๋ฆฌ ํ•„์š”
์‚ฌ์šฉ ๋Œ€์ƒ ๊ฐ’ (VALUE) ์ปฌ๋Ÿผ๋ช…, ํ…Œ์ด๋ธ”๋ช…, ์ •๋ ฌ ๋ฐฉํ–ฅ
์ฃผ ์šฉ๋„ ์ผ๋ฐ˜์ ์ธ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ ๋™์  SQL ๊ตฌ์กฐ ๋ณ€๊ฒฝ

5. SQL Injection ์œ„ํ—˜์„ฑ

${}์˜ SQL Injection ์œ„ํ—˜์„ ์‹ค์ œ ์˜ˆ์‹œ๋กœ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

๊ณต๊ฒฉ ์‹œ๋‚˜๋ฆฌ์˜ค

<!-- ${} ์‚ฌ์šฉ ์‹œ -->
SELECT * FROM users WHERE name = '${name}'
๊ณต๊ฒฉ์ž๊ฐ€ name์— ์•„๋ž˜ ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด:
' OR '1' = '1

์ฟผ๋ฆฌ๊ฐ€ ์ด๋ ‡๊ฒŒ ๋ณ€ํ•จ:
SELECT * FROM users WHERE name = '' OR '1' = '1'
→ ์กฐ๊ฑด์ด ํ•ญ์ƒ TRUE → ์ „์ฒด ๋ฐ์ดํ„ฐ ์กฐํšŒ โŒ

 

 

#{} ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ์ „ํ•œ ์ด์œ 

<!-- #{} ์‚ฌ์šฉ ์‹œ -->
SELECT * FROM users WHERE name = #{name}
๊ณต๊ฒฉ์ž๊ฐ€ name์— ์•„๋ž˜ ๊ฐ’์„ ์ž…๋ ฅํ•ด๋„:
' OR '1' = '1

PreparedStatement๊ฐ€ ๊ฐ’ ์ž์ฒด๋กœ ์ฒ˜๋ฆฌ:
SELECT * FROM users WHERE name = ?
→ ? ์— "' OR '1' = '1" ๋ฌธ์ž์—ด ์ž์ฒด๊ฐ€ ๋ฐ”์ธ๋”ฉ
→ SQL ๊ตฌ์กฐ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€ โœ…

6. ${} ์‚ฌ์šฉ ์‹œ ๋ฐ˜๋“œ์‹œ ์„œ๋ฒ„์—์„œ ๊ฒ€์ฆ

${}๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋ฐ–์— ์—†๋Š” ๊ฒฝ์šฐ, ์„œ๋ฒ„์—์„œ ํ—ˆ์šฉ๋œ ๊ฐ’์ธ์ง€ ๋ฐ˜๋“œ์‹œ ๊ฒ€์ฆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

โŒ ๋ฐฑ์—”๋“œ์—์„œ SQL Injection์„ ์ง์ ‘ ๋ฐฉ์–ดํ•˜๋Š” ๊ฑด ์ข‹์ง€ ์•Š๋‹ค

// โŒ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ๋ฐฉ์‹ — ๊ถŒ์žฅํ•˜์ง€ ์•Š์Œ
public String sanitize(String input) {
    return input
        .replace("'", "''")
        .replace("--", "")
        .replace(";", "")
        .replace("/*", "")
        .replace("*/", "");
        // ๊ณต๊ฒฉ ํŒจํ„ด์€ ๋ฌด๊ถ๋ฌด์ง„ → ํ•˜๋‚˜๋ผ๋„ ๋†“์น˜๋ฉด ๋šซ๋ฆผ
}

SQL Injection ๊ณต๊ฒฉ ํŒจํ„ด์€ ๋งค์šฐ ๋‹ค์–‘ํ•ด์„œ ๋ชจ๋“  ์ผ€์ด์Šค๋ฅผ ์ง์ ‘ ๋ง‰๋Š” ๊ฑด ์‚ฌ์‹ค์ƒ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
ํ•˜๋‚˜๋ผ๋„ ๋†“์น˜๋ฉด ์ทจ์•ฝ์ ์ด ๋ฉ๋‹ˆ๋‹ค.

#{} ์™€ ${} ์˜ ๋ฐฉ์–ด ๋ฐฉ์‹ ์ฐจ์ด

${} + ๋ฐฑ์—”๋“œ ์ง์ ‘ ๊ฒ€์ฆ
  ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๊ตฌํ˜„ → ์‹ค์ˆ˜/๋ˆ„๋ฝ ๊ฐ€๋Šฅ์„ฑ → ์ทจ์•ฝ์  ๋ฐœ์ƒ ๊ฐ€๋Šฅ

#{}
  JDBC PreparedStatement → DB ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ์›์ฒœ ์ฐจ๋‹จ → ์™„์ „ ์•ˆ์ „

#{} ๋Š” ๊ฐ’์„ SQL ๊ตฌ์กฐ์™€ ์™„์ „ํžˆ ๋ถ„๋ฆฌํ•ด์„œ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์—
์•„๋ฌด๋ฆฌ ์•…์˜์ ์ธ ๊ฐ’์ด ๋“ค์–ด์™€๋„ SQL ๊ตฌ์กฐ ์ž์ฒด๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

${} ๋ฅผ ์จ์•ผ ํ•œ๋‹ค๋ฉด ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๋ฐฉ์‹์œผ๋กœ

// โœ… ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๋ฐฉ์‹ (๊ถŒ์žฅ)
public List<UserDto> getUserList(String sortColumn, String sortDirection) {

    // ํ—ˆ์šฉ๋œ ์ปฌ๋Ÿผ๋ช…๋งŒ ํ—ˆ์šฉ
    List<String> allowedColumns = List.of("name", "age", "created_at");
    if (!allowedColumns.contains(sortColumn)) {
        throw new IllegalArgumentException("ํ—ˆ์šฉ๋˜์ง€ ์•Š์€ ์ •๋ ฌ ์ปฌ๋Ÿผ์ž…๋‹ˆ๋‹ค.");
    }

    // ํ—ˆ์šฉ๋œ ๋ฐฉํ–ฅ๋งŒ ํ—ˆ์šฉ
    if (!sortDirection.equalsIgnoreCase("ASC")
            && !sortDirection.equalsIgnoreCase("DESC")) {
        throw new IllegalArgumentException("ํ—ˆ์šฉ๋˜์ง€ ์•Š์€ ์ •๋ ฌ ๋ฐฉํ–ฅ์ž…๋‹ˆ๋‹ค.");
    }

    return userMapper.getUserList(sortColumn, sortDirection);
}
๋ฐฉ์‹ ์„ค๋ช… ๊ถŒ์žฅ ์—ฌ๋ถ€
#{} ์‚ฌ์šฉ DB ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ์›์ฒœ ์ฐจ๋‹จ โœ… ํ•ญ์ƒ ๊ถŒ์žฅ
ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๊ฒ€์ฆ ํ—ˆ์šฉ๋œ ๊ฐ’ ๋ชฉ๋ก์œผ๋กœ๋งŒ ํ—ˆ์šฉ โœ… ${} ํ•„์ˆ˜ ์‹œ ๊ถŒ์žฅ
๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ๊ฒ€์ฆ ์œ„ํ—˜ํ•œ ๋ฌธ์ž์—ด ์ง์ ‘ ์ œ๊ฑฐ โŒ ๋น„๊ถŒ์žฅ

 


7. ์‹ค๋ฌด ํ™œ์šฉ ์˜ˆ์‹œ

CDATA + #{} + ${} ํ•จ๊ป˜ ์‚ฌ์šฉ

<select id="getUserList" resultType="UserDto">
    SELECT
        user_id,
        name,
        email,
        age,
        salary
    FROM users
    <where>
        <if test="name != null and name != ''">
            AND name LIKE #{name}
        </if>
        <if test="minAge != null">
            <![CDATA[ AND age >= #{minAge} ]]>      <!-- >= ํŠน์ˆ˜๋ฌธ์ž CDATA ์ฒ˜๋ฆฌ -->
        </if>
        <if test="maxSalary != null">
            <![CDATA[ AND salary <= #{maxSalary} ]]> <!-- <= ํŠน์ˆ˜๋ฌธ์ž CDATA ์ฒ˜๋ฆฌ -->
        </if>
        <if test="status != null">
            AND status = #{status}
        </if>
    </where>
    ORDER BY ${sortColumn} ${sortDirection}          <!-- ๋™์  ์ •๋ ฌ ${}  -->
</select>

 

Oracle IN ์ ˆ ์ฒ˜๋ฆฌ

<select id="getUserByIds" resultType="UserDto">
    SELECT *
    FROM users
    WHERE user_id IN
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}   <!-- foreach ์•ˆ์—์„œ๋„ #{} ์‚ฌ์šฉ -->
    </foreach>
</select>

 


8. ์ตœ์ข… ์ •๋ฆฌ

ํ•ญ๋ชฉ CDATA #{} ${}
์šฉ๋„ XML ํŠน์ˆ˜๋ฌธ์ž ์ฒ˜๋ฆฌ ๊ฐ’ ๋ฐ”์ธ๋”ฉ ๋ฌธ์ž์—ด ์ง์ ‘ ์น˜ํ™˜
SQL Injection ํ•ด๋‹น ์—†์Œ โœ… ์•ˆ์ „ โŒ ์œ„ํ—˜
์‚ฌ์šฉ ๋Œ€์ƒ <, >, & ํฌํ•จ SQL ๊ฐ’(VALUE) ์ปฌ๋Ÿผ๋ช…, ํ…Œ์ด๋ธ”๋ช…
์ฃผ์˜์‚ฌํ•ญ ๋‚ด๋ถ€์— MyBatis ํƒœ๊ทธ ๋ถˆ๊ฐ€ ์—†์Œ ๋ฐ˜๋“œ์‹œ ์„œ๋ฒ„ ๊ฒ€์ฆ ํ•„์š”

 

๊ฐ’์„ ๋ฐ”์ธ๋”ฉ ํ• ๋•Œ๋Š” ํ•ญ์ƒ #{} ์„ ์‚ฌ์šฉํ•˜๊ณ ,
์ปฌ๋Ÿผ๋ช…์ด๋‚˜ ํ…Œ์ด๋ธ”๋ช…์ฒ˜๋Ÿผ ๊ตฌ์กฐ์ ์ธ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•  ๋•Œ๋งŒ ${} ๋ฅผ ์‚ฌ์šฉํ•˜๋˜, ๋ฐ˜๋“œ์‹œ ์„œ๋ฒ„์—์„œ ๊ฒ€์ฆ์„ ๊ฑฐ์ณ์•ผ ํ•œ๋‹ค.
<, > ์™€ ๊ฐ™์€ XML ํŠน์ˆ˜๋ฌธ์ž๊ฐ€ SQL์—์„œ ํ•„์š”ํ•˜๋‹ค๋ฉด CDATA๋กœ ๊ฐ์‹ธ์„œ ์‚ฌ์šฉํ•˜๊ธฐ !

 

'๐Ÿ–ฅ๏ธ development' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Oracle Synonym(์‹œ๋…ธ๋‹˜)  (0) 2026.05.25
๋‚ด์žฅ Tomcat vs ์™ธ๋ถ€ Tomcat  (0) 2026.05.15
'๐Ÿ–ฅ๏ธ development' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • Oracle Synonym(์‹œ๋…ธ๋‹˜)
  • ๋‚ด์žฅ Tomcat vs ์™ธ๋ถ€ Tomcat
Dream Jin
Dream Jin
Coder๊ฐ€ ์•„๋‹Œ Engineer ๋˜๊ธฐ์œ„ํ•ด ์‹œ์ž‘ํ•˜๊ธฐ
  • Dream Jin
    JJin ๊ฐœ๋ฐœ Vlog (~23.01.02)
    Dream Jin
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (57)
      • Daily (3)
      • ๐Ÿ–ฅ๏ธ development (29)
        • JAVA (11)
        • Java Script (11)
        • SQL (4)
      • Computer Science (0)
      • IT (8)
      • ์ž๋ฃŒ๊ตฌ์กฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (16)
        • ์•Œ๊ณ ๋ฆฌ์ฆ˜ (9)
        • ์ž๋ฃŒ๊ตฌ์กฐ (6)
      • Project (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • github
    • instagram
    • ๋ฐฉ๋ช…๋ก
  • ์ธ๊ธฐ ๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.
Dream Jin
MyBatis XML — CDATA, #{}, ${}
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”