<< 학습 목표 >>

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 태그를 활용할 수 있음

728x90
LIST