<< 학습 목표 >>
1. where 태그를 활용할 수 있다.
전 글 ( https://codingaja.tistory.com/119 ) 에서 작성한 동적 쿼리 중에는 문제의 소지가 있는 쿼리가 있음
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.study.chapter04.MemberDao">
// ...
<select id="selectMember" parameterType="com.study.chapter04.SelectMemberDto" resultType="com.study.chapter04.SelectMemberDto">
SELECT * FROM member WHERE nickname IN
<foreach collection="selectConditions" item="condition" open="(" close=")" separator=", ">
#{condition.nickname}
</foreach>
;
</select>
// ...
</mapper>
이 쿼리는 DAO가 쿼리쪽으로 데이터들을 전달해준다 라는 전제조건 하에 짜여진 동적 쿼리임
DAO가 쿼리쪽으로 데이터들을 전달해주지 않으면 어떻게 될까?
더 정확하게 이해를 하기 위해 컨트롤러부터 보자
<< 컨트롤러 >>
package com.study.chapter04;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MyBatisController {
@Autowired
private MemberDao memberDao;
// ...
@GetMapping("/chapter04/mybatis/member")
public void getMemberByNickname(String nickname) {
System.out.println("<< 닉네임으로 회원 정보 조회 시작 >>");
// 닉네임으로 회원 정보 조회
List<SelectMemberDto> member = memberDao.selectMember(null);
// 조회한 회원 정보 출력
System.out.println(member);
System.out.println("<< 닉네임으로 회원 정보 조회 종료 >>");
}
// ...
}
<< 코드 설명 >>
(1). 컨트롤러는 DAO 측으로 null 을 전달하고 있음
<< DAO >>
package com.study.chapter04;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MemberDao {
// ...
List<SelectMemberDto> selectMember(List<SelectMemberDto> selectConditions);
// ...
}
<< 코드 설명 >>
(1). 컨트롤러가 DAO로 null을 전달했으므로 DAO도 쿼리쪽으로 selectionCondition을 null로 전달함
<< 쿼리 설명 >>
쿼리에서는 null 상태인 selectionConditions 를 사용해 반복문을 동작시키려 하므로 NullPointerException이 발생할 수 있음
이걸 해결하는 방법은 무엇일까?
방법1. foreach를 if문으로 감싼다.
그러나 이 방법은 잘못된 방법임
selectCondition의 값이 null 일 때 만들어지는 쿼리가 [ SELECT * FROM WHERE nickname IN ] 이와 같으므로 SQL 문법 오류가 생겨 SQLException이 발생할 수 있음
방법2. WHERE 를 if문으로 감싼다.
selectConditions가 null이 아니라면 WHERE 절이 붙고 in 에 들어갈 값은 foreach문을 통해 들어가게 됨
WHERE절을 동적으로 구성할 때 위와 같이 해도 되지만 프로그램의 규모가 커져 WHERE절이 점점 더 복잡해진다면 더 이상 위와 같은 동적 쿼리로는 WHERE 절을 구성할 수 없게됨
복잡한 WHERE 절을 동적 쿼리로 구성할 때는 where 태그를 사용함
태그명 | where |
설명 | WHERE 절을 동적으로 구성하고 싶을 때 사용하는 태그 WHERE 태그 안에 어떤 구문이 들어있다면 WHERE절을 붙여 해당 구문을 쿼리에 추가함 WHERE 태그 안에 아무 구문도 들어있지 않다면 WHERE절이 붙지 않음 WHERE 절 안에 어떤 구문이 AND 또는 OR 등으로 시작한다면 SQL문법에 오류가 발생하므로 이런 부분을 방지하기 위해 어떤 구문이 AND 또는 OR 등으로 시작한다면 해당 AND, OR 등만 지워줌 |
속성 | 없음 |
우선 간단하면서 직관적인 두 예를 보며 WHERE 절에 대해서 알아보자
1. WHERE 태그 안에 아무 구문도 들어있지 않는 경우
이런 경우 SELECT 쿼리에 WHERE 절이 붙지 않음
따라서 만들어지는 쿼리는 [ SELECT * FROM member; ] 임
2. WHERE 태그 안에 어떤 구문이 들어있는 경우
이런 경우 SELECT 쿼리에 WHERE 절이 붙음
따라서 만들어지는 쿼리는 [ SELECT * FROM member WHERE nickname IN ("홍길동", "김철수", "고영희"); ] 임
이제 where태그를 본격적으로 사용해보자
본격적이라고는 했지만 굉장히 간단함
1. where 태그와 if 태그를 함께 사용 하는 상황
회원 정보를 검색할 때 필터 기능이 있어 아이디, 닉네임, 연락처로 회원 정보를 검색할 수 있는 상황이라고 하자
검색 조건을 아무것도 설정하지 않아 전체 회원을 조회할 수도 있고 한 항목만 사용될 수도 있고 모든 항목이 다 사용될 수도 있음
여러 항목이 검색 조건으로 사용됐을 때는 검색 조건들이 모두 OR 로 묶여야 되는 상황임
이런 상황은 where 태그와 if 태그를 사용해 해결할 수 있을 것
<select id="selectMember" parameterType="com.study.chapter04.SelectMemberDto" resultType="com.study.chapter04.SelectMemberDto">
SELECT * FROM member
<where>
<if test="id != null">
id = #{id}
</if>
<if test="nickname != null">
OR nickname = #{nickname}
</if>
<if test="tel != null">
OR tel = #{tel}
</if>
</where>
;
</select>
<< 코드 설명 >>
위 쿼리에서 만들어질 수 있는 쿼리는 7가지임
1. 아이디, 닉네임, 연락처 모두 없을 경우
-> SELECT * FROM member;
2. 아이디만 있을 경우
-> SELECT * FROM member WHERE id = #{id}
3. 닉네임만 있을 경우
-> SELECT * FROM member WHERE nickname = #{nickname}
4. 연락처만 있을 경우
-> SELECT * FROM member WHERE tel = #{tel}
5. 아이디, 닉네임만 있을 경우
-> SELECT * FROM member WHERE id = #{id} OR nickname = #{nickname}
6. 아이디, 닉네임, 연락처 모두 있을 경우
-> SELECT * FROM member WHERE id = #{id} OR nickname = #{nickname} OR tel = #{tel}
7. 닉네임, 연락처만 있을 경우
-> SELECT * FROM member WHERE nickname = #{nickname} OR tel = #{tel}
아이디가 있는 상황 ( 2, 5, 6 ) 에서는 당연히 id = #{id} 로 시작함
그러나 닉네임 또는 연락처가 있는 상황 ( 3, 4, 7 ) 에서는 OR 가 먼저 와야 할 것같지만 맨 앞에 있는 OR 는 삭제 됐음
where 태그는 맨 앞에 AND 또는 OR 가 오면 삭제함
trim 태그를 사용해서 where 태그와 똑같이 표현할 수 있음
<select id="selectMember" parameterType="com.study.chapter04.SelectMemberDto" resultType="com.study.chapter04.SelectMemberDto">
SELECT * FROM member
<trim prefix="WHERE" prefixOverrides="AND | OR">
<if test="id != null">
id = #{id}
</if>
<if test="nickname != null">
OR nickname = #{nickname}
</if>
<if test="tel != null">
OR tel = #{tel}
</if>
</trim>
;
</select>
2. where 태그와 foreach 태그를 함께 사용하는 상황
회원 정보를 검색할 때 필터 기능이 있어 닉네임들로 회원 정보를 검색할 수 있는 상황이라고 하자
닉네임을 입력하지 않고 전체 회원 정보를 검색할 수도 있고 닉네임을 하나만 입력해 한 회원의 정보만 검색할 수도 있으며 여러 닉네임을 입력해 여러 회원의 정보를 검색할 수도 있음
이런 상황은 where 태그와 if, foreach 태그를 함께 사용해 해결 할 수 있을 것
<select id="selectMember" parameterType="com.study.chapter04.SelectMemberDto" resultType="com.study.chapter04.SelectMemberDto">
SELECT * FROM member
<where>
<if test="nicknames != null">
nickname IN
<foreach collection="nicknames" item="nickname" open="(" close=")" separator=", ">
#{nickname}
</foreach>
</if>
</where>
;
</select>
여기까지 where 태그를 활용하는 방법을 알아봤음
여기서 알아본 방법 외에도 전 글 ( https://codingaja.tistory.com/119 ) 에서 배운 동적 쿼리와 함께 사용하면 만들고 싶은 모든 쿼리를 다 만들 수 있음
또한 여기서는 SELECT 쿼리에서만 where 태그 를 사용했지만
UPDATE, DELETE 역시 WHERE 절이 있으므로 UPDATE, DELETE 에서도 where 태그를 활용할 수 있음
'Spring + Boot > Boot-Chapter04' 카테고리의 다른 글
Chapter04. Spring Boot - DB / MyBatis 심화, bind, resultMap 동적 쿼리 (0) | 2023.05.29 |
---|---|
Chapter04. Spring Boot - DB / MyBatis 심화, SET 동적 쿼리 (0) | 2023.05.28 |
Chapter04. Spring Boot - DB / MyBatis 심화, 동적 쿼리 (0) | 2023.05.28 |
Chapter04. Spring Boot - DB / MyBatis 심화, INSERT 시 PK값 돌려받기 (0) | 2023.05.27 |
Chapter04. Spring Boot - DB / MyBatis 기본, 쿼리 결괏값 사용하기 (2) | 2023.05.26 |