본문 바로가기

BackEnd/Spring

[코드로 배우는 스프링 웹 프로젝트] ch15 검색 처리 1(sql, MyBatis 동적 태그)

728x90
반응형

◎ 검색 조건

   ▷ <select> 태그를 이용하거나 <checkbox> 이용하는 경우가 많음

   ▷ 최근 일반 웹사이트 사용자들의 경우 <selec>를 사용, 관리자용이나 검색 기능이 강한 경우 <checkbox> 이용

 

1. 검색 기능과 SQL

   ▷ 게시물 검색 기능은 다음과 같이 분류 가능

      ▶ 제목/내용/작성자와 같이 단일 항목 검색

      ▶ 제목 or 내용, 제목 or 작성자, 내용 or 작성자, 제목 or 내용 or 작성자와 같은 다중 항목 검색

 


where문 뒤에 검색 조건이 추가되고, rownum 조건이 뒤따르게 하면 문제가 없음

 

(1) 다중 항목 검색

   ▷ 2개 이상의 조건이 붙는 다중 항목의 검색이 문제

 

◎ 제목이나 내용 중에 'TEST'라는 문자열이 있는 게시물들을 검색하는 SQL

select
*
from
	(
		select /*+ INDEX_DESC(tbl_board pk_board) */
			rownum rn, bno, title, content, writer, regdate, updatedate
		from
			tbl_board
		where
			title like '%테스트%' or content like '%테스트%'
			and rownum <= 20
	)
where rn > 10;


▷ 구문 자체는 이상이 없지만, 실제로 동작 시켜보면 10개의 데이터가 아니라 많은 양의 데이터가 나오는 것 확인 가능


많은 양의 데이터가 나온 이유는 위 SQL문에서 AND 연산자가 OR 연산자 보다 우선 순위가 높기 때문에
'ROWNUM이 20보다 작거나 같은면서(AND) 내용에 '테스트'라는 문자열이 있는 게시물들을 검색

제목에 '테스트'라는 문자열이 있는 경우는 많기 때문에 위의 그림과 같이 많은 양의 데이터를 가져옴


◎ 따라서 우선 순위 연산자인 '( )'를 이용해서 OR 조건을 처리해야 함

 

select
*
from
	(
		select /*+ INDEX_DESC(tbl_board pk_board) */
			rownum rn, bno, title, content, writer, regdate, updatedate
		from
			tbl_board
		where
			(title like '%테스트%' or content like '%테스트%')
			and rownum <= 20
	)
where rn > 10;



결과를 확인하면 원하는 10개의 데이터만 출력되는 것을 볼 수 있음

 

 

2. MyBatis의 동적 SQL

   ▷ 검색 조건이 변하면 SQL 내용 역시 변하기 때문에 XML이나 어노테이션 같이 고정된 문자열을 작성하는 방식으로 제대로 처리할 수 없음

   ▷ MyBatis는 동적(Dynamic) 태그 기능을 통해 SQL을 파라미터들의 조건에 맞게 조정할수 있음

 

(1) MyBatis의 동적 태그들

   ▷ if

   ▷ choose(when, otherwise)

   ▷ trim(where, set)

   ▷ foreach

 

 

◎ if

   ▷ test라는 속성과 함께 특정한 조건이 true가 되었을 때 포함된 SQL을 사용하고자할 때 작성

   ▷ 단일 항목으로 제목(title), 내용(content), 작성자(writer)에 대해 검색해야하는 상황

1. 검색 조건이 'I'면 제목(title)이 키워드인 항목을 검색
2. 검색 조건이 'C'면 내용(content)이 키워드인 항목을 검색
3. 검색 조건이 'W'면 작성자(writer)이 키워드인 항목을 검색

MyBatis는 XML에서 다음과 같이 작성할 수 있음
<if test="type == 'T'.toString()">
	(title like '%' || #{keyword} || '%')
</if>
<if test="type == 'C'.toString()">
	(title like '%' || #{keyword} || '%')
</if>
<if test="type == 'W'.toString()">
	(title like '%' || #{keyword} || '%')
</if>​


If 안에 들어가는 표현식(expression)은 OGNL 표현식이라는 것을 이용
좀 더 자세한 내용은 https://commons.apache.org/proper/commons-ognl/language-guide.html 참고

 

◎ choose

   ▷ if와 달리 choose는 여러 상황들 중 하나의 상황에서만 동작

   ▷ Java 언어의 'if ~ else'나 JSTL의 choose와 유사

<choose>
<when test="type == 'T'.toString()">
	(title like '%' || #{keyword} || '%')
</when>
<when test="type == 'C'.toString()">
	(title like '%' || #{keyword} || '%')
</when>
<when test="type == 'W'.toString()">
	(title like '%' || #{keyword} || '%')
</when>
<otherwise>
	(title like '%' || #{keyword} || '%' OR content lilke '%' || #{keyword} || '%')
</otherwise>
</choose>


<otherwise>는 위의 모든 조건이 충족되지 않을 경우에 사용함

 

◎ trim, where, set

   ▷ 단독으로 사용되지 않고 <if>, <choose>와 같은 태그들을 내포하여 SQL들을 연결

   ▷ 앞 뒤에 필요한 구문들(AND, OR, WHERE 등)을 추가하거나 생략하는 역할

 

◎ 문제 발생 예시

▷ 'WHERE ROWNUM <= 20'은 문제가 없지만 검색 조건이 들어가면 문제가 될 수 있습니다.


검색 조건이 없다면 AND가 필요 없지만, 검색 조건이 추가되면 AND가 필요한 상황이 됨

where, trim, set은 이런 상황에서 필요한 키워드를 붙이거나 빼는 상황에서 사용 

 

◎ <where>

   ▷ 태그 안쪽에서 SQL이 생성될 때 WHERE 구문이 붙고, 그렇지 않는 경우에는 생성되지 않음

select * from tbl_board
	<where>
		<if test="bno != null">
		bno = #{bno}
		</if>
	</where>​


bno 값이 null인 경우 where 구문이 없어지고, bno 값이 존재하는 경우에만 'where bno = xx'와 같이 생성됨

 

◎ <trim>

   ▷ 하위에서 만들어지는 SQL 문을 조사해 앞 쪽에 추가적인 SQL을 넣을 수 있음

select * from tbl_board
	<where>
		<if test="bno != null">
		bno = #{bno}
		</if>
        <trim prefix="and">
        rownum = 1
        </trim>
	</where>


prefix, suffix, prefixOverrides, suffixOverrides 속성 지정 가능

 

 

◎ <foreach>

   ▷ List, 배열, 맵 등을 이용해 루프 처리 가능

   ▷ 주로 IN 조건에서 많이 사용하지만, 경우에 따라서 복잡한 WHERE 조건을 만들때에도 사용할 수 있음

 

◎ 예시) 제목('T')은 'TTTT'로 내용('C')은 'CCCC'라는 값을 이용한다면 Map의 형태로 작성 가능

Map<String, String> map = new HashMap<>();
map.put("T", "TTTT");
map.put("C", "CCCC");​

작성된 Map을 파라미터로 전달하고, foreach를 이용하면 다음과 같은 형식이 가능
select * from tbl_board
	<trim prefix="where ("suffix=")" prefixOverrides="OR">
		<foreach item="val" index="key" collection="map">
        
			<trim prefix = "OR">
				<if test="key == 'C'.toString()">
					content = #{val}
				</if>
				<if test="key == 'T'.toString()">
					content = #{val}
				</if>
				<if test="key == 'W'.toString()">
					content = #{val}
				</if>
			</trim>
		</foreach>
	</trim>​


foreach를 배열이나 List를 이용하는 경우 item 속성만 이용하면 되고, Map의 형태로 key와 value를 이용해야 할 때는 index와 item 속성을 둘 다 이용합니다.

select * from tbl_board
	where(content = ?
	OR title = ?)
	
INFO : jdbc.sqlonly - select * from tbl_board where (content = 'CCCC' OR title = 'TTTT')

 

검색 기능을 이용하기 위해서 SQL에서 나타나는 방법과 spring에서 해당 구문들, MaBatis를 이용한 동적 태그들을 구현하는 방법에 대해서 배워보았습니다.

 

괄호의 역할이 중요한 것 같고 해당 구문도 잘 이용해야할 것 같아요!

 

이어서 검색 기능을 구현해보겠습니다!!

 

많은 분들의 피드백은 언제나 환영합니다!  많은 댓글 부탁드려요~~

 

728x90
반응형