MyBatis: WHERE 1=1 대신 trim으로 해결하기
MyBatis: WHERE 1=1 대신 trim으로 해결하기
동적 조건 검색의 단골 패턴, WHERE 1=1
MyBatis로 검색 쿼리를 짜다 보면, 조건이 선택적으로 붙는 경우가 많습니다. 이름이 있으면 이름으로, 상태가 있으면 상태로 거는 식이죠. 이때 흔히 쓰는 게 WHERE 1=1 입니다.
1
2
3
4
5
6
7
8
9
10
<select id="search" resultType="User">
SELECT * FROM users
WHERE 1=1
<if test="name != null">
AND name = #{name}
</if>
<if test="status != null">
AND status = #{status}
</if>
</select>
WHERE 1=1을 둔 이유는, 조건이 하나도 없거나 AND로 시작해도 SQL이 깨지지 않게 하기 위함입니다. 첫 조건 앞의 AND를 1=1이 받아주니까요.
WHERE 1=1의 문제
동작은 하지만 찜찜한 점이 있습니다.
- 항상 참인
1=1이 쿼리에 남아 의미 없는 조건이 붙습니다. - 가독성이 떨어지고, “왜 1=1이 있지?”를 모르는 사람에겐 혼란.
- 깔끔한 SQL을 지향한다면 군더더기.
해결 1: <where> 태그
MyBatis의 <where> 태그는 내부에 조건이 하나라도 있을 때만 WHERE를 붙이고, 맨 앞의 AND/OR를 자동으로 제거해줍니다.
1
2
3
4
5
6
7
8
9
10
11
<select id="search" resultType="User">
SELECT * FROM users
<where>
<if test="name != null">
AND name = #{name}
</if>
<if test="status != null">
AND status = #{status}
</if>
</where>
</select>
- 조건이 하나도 없으면 →
WHERE자체가 안 붙음. - 첫 조건이
AND name = ...이어도 → 앞의AND를 떼서WHERE name = ...로.
1=1 없이도 깔끔하게 해결됩니다.
해결 2: <trim> 태그 (더 유연)
<where>는 사실 <trim>의 특수한 형태입니다. <trim>은 접두사/접미사를 직접 제어할 수 있어 더 유연합니다.
1
2
3
4
5
6
7
8
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="name != null">
AND name = #{name}
</if>
<if test="status != null">
AND status = #{status}
</if>
</trim>
prefix="WHERE": 내용이 있으면 앞에WHERE를 붙임.prefixOverrides="AND |OR ": 내용 맨 앞의AND또는OR를 제거.
UPDATE의 SET 절에도 같은 원리로 <set> 태그(또는 <trim prefix="SET" suffixOverrides=",">)를 써서 끝의 쉼표를 제거할 수 있습니다.
1
2
3
4
5
6
7
8
<update id="update">
UPDATE users
<set>
<if test="name != null">name = #{name},</if>
<if test="status != null">status = #{status},</if>
</set>
WHERE id = #{id}
</update>
정리
WHERE 1=1은 동작하지만 군더더기다.<where>: 조건 있을 때만WHERE, 맨 앞AND/OR자동 제거.<trim>:prefix/prefixOverrides로 더 유연하게 제어(<where>의 일반형).UPDATE엔<set>으로 끝 쉼표 정리. 깔끔한 동적 SQL을 만들자.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.
