[MyBatis] 동적쿼리를 사용한 예외처리 (if, choose, when, otherwise)

Yeoonnii·2022년 11월 9일
0

MyBatis

목록 보기
8/10
SELECT COUNT (*) FROM(
SELECT  R.LIKECOUNT, RR.REPLYCOUNT, B.BNO, B.CONTENT, B.HIT, B.REGDATE, B.TITLE, B.USERID, ROW_NUMBER() OVER (ORDER BY RR.REPLYCOUNT DESC, REGDATE DESC) ROWN FROM
                (SELECT DISTINCT BNO 
        	FROM HASHTAGMAPPING HM WHERE HM.HNO IN (HNO OR 1,2,3) ORDER BY BNO DESC
        ) BM
        INNER JOIN BOARD B ON BM.BNO = B.BNO
        INNER JOIN (SELECT BNO, COUNT(USERID) LIKECOUNT FROM LIKES GROUP BY BNO) R ON R.BNO = B.BNO
        INNER JOIN (SELECT BNO, COUNT(RNO) REPLYCOUNT FROM REPLY GROUP BY BNO) RR ON RR.BNO = B.BNO
        WHERE (B.TITLE LIKE '%' || 'T' || '%' OR B.CONTENT LIKE '%' || 'C' || '%'))

위 쿼리문을 XML에서 사용시 프론트에서 HNO를 파라미터로 주지 않는 경우 HM.HNO IN (HNO OR ) 형태가 되어 DB조회가 되지 않는 문제가 발생한다
⇒ XML에서 IF문 으로 HNO 파라미터 값이 없는경우 조회가 가능하도록 처리해준다

WHERE HM.HNO IN (HNO OR 1,2,3) ⇒ 이 부분을 if문 처리하여
hno != null 인 경우 where 조건 : WHERE HM.HNO IN (1,2,3)
hno == null 인 경우 where 조건 : WHERE HM.HNO IN (HNO)
* 참고! IN 뒤에는 null이 올 수 없다



오류

수정전 오류발생한 쿼리문

HNOnull인 경우 예외처리를 하지 않아 발생한 오류이다

<select id="boardSelectMain" parameterType="map" resultType="com.example.dto.BoardMainDTO">
        SELECT * FROM 
        (SELECT M.NICKNAME, R.LIKECOUNT, RR.REPLYCOUNT, B.BNO, B.CONTENT, B.HIT, B.REGDATE, B.TITLE, B.USERID, ROW_NUMBER() OVER (ORDER BY ${type} B.REGDATE DESC) ROWN FROM
                (SELECT DISTINCT BNO
                FROM HASHTAGMAPPING HM WHERE HM.HNO IN ( 
                        <choose>
                           <when test="hno != null">
                                <foreach collection="hno" item="tmp" separator = ", ">
                                    #{tmp}
                                </foreach>
                           </when>
                           <otherwise>
                                HNO
                           </otherwise>
                        </choose>
                        ) ORDER BY BNO DESC
                        ) BM
                INNER JOIN BOARD B ON BM.BNO = B.BNO
                INNER JOIN MEMBER M ON M.USERID = B.USERID
                INNER JOIN (SELECT BNO, COUNT(USERID) LIKECOUNT FROM LIKES GROUP BY BNO) R ON R.BNO = B.BNO
                INNER JOIN (SELECT BNO, COUNT(RNO) REPLYCOUNT FROM REPLY GROUP BY BNO) RR ON RR.BNO = B.BNO
                WHERE (B.TITLE LIKE '%' || #{title} || '%' OR B.CONTENT LIKE '%' || #{content} || '%')
        )
        WHERE ROWN BETWEEN #{page} AND #{page}+11 ORDER BY ROWN

오류메세지



해결

1. 예외처리 할 부분 찾기

[ a. 해시태그 선택하지 않은 경우 동작 되어야 하는 쿼리문 ] 과
[ b. 해시태그 선택한 경우 동작 되어야 하는 쿼리문 ] 을 작성하여
예외처리가 되어야 할 부분을 찾는다


a. 해시태그 선택하지 않은 경우 동작 되어야 하는 쿼리문

SELECT  R.LIKECOUNT, RR.REPLYCOUNT, B.BNO, B.CONTENT, B.HIT, B.REGDATE, B.TITLE, B.USERID, ROW_NUMBER() OVER (ORDER BY RR.REPLYCOUNT DESC, REGDATE DESC) ROWN FROM
                (SELECT DISTINCT BNO 
        	FROM HASHTAGMAPPING HM 
        	ORDER BY BNO DESC
        ) BM
        INNER JOIN BOARD B ON BM.BNO = B.BNO
        INNER JOIN (SELECT BNO, COUNT(USERID) LIKECOUNT FROM LIKES GROUP BY BNO) R ON R.BNO = B.BNO
        INNER JOIN (SELECT BNO, COUNT(RNO) REPLYCOUNT FROM REPLY GROUP BY BNO) RR ON RR.BNO = B.BNO
        WHERE (B.TITLE LIKE '%' || 'T' || '%' OR B.CONTENT LIKE '%' || 'C' || '%')

b. 해시태그 선택한 경우 동작 되어야 하는 쿼리문

SELECT  R.LIKECOUNT, RR.REPLYCOUNT, B.BNO, B.CONTENT, B.HIT, B.REGDATE, B.TITLE, B.USERID, ROW_NUMBER() OVER (ORDER BY RR.REPLYCOUNT DESC, REGDATE DESC) ROWN FROM
                (SELECT DISTINCT BNO 
        	FROM HASHTAGMAPPING HM 
                WHERE HM.HNO IN (1,4) 
                ORDER BY BNO DESC
        ) BM
        INNER JOIN BOARD B ON BM.BNO = B.BNO
        INNER JOIN (SELECT BNO, COUNT(USERID) LIKECOUNT FROM LIKES GROUP BY BNO) R ON R.BNO = B.BNO
        INNER JOIN (SELECT BNO, COUNT(RNO) REPLYCOUNT FROM REPLY GROUP BY BNO) RR ON RR.BNO = B.BNO
        WHERE (B.TITLE LIKE '%' || 'T' || '%' OR B.CONTENT LIKE '%' || 'C' || '%')


2. if문 사용하여 xml에서 예외처리 하기

boardMapper.xml

<select id="boardSelectMain" parameterType="map" resultType="com.example.dto.BoardMainDTO">
        SELECT * FROM 
        (SELECT M.NICKNAME, R.LIKECOUNT, RR.REPLYCOUNT, B.BNO, B.CONTENT, B.HIT, B.REGDATE, B.TITLE, B.USERID, ROW_NUMBER() OVER (ORDER BY ${type} B.REGDATE DESC) ROWN FROM
                (SELECT DISTINCT BNO
                FROM HASHTAGMAPPING HM
                        <if test="hno != null"> 
                                WHERE HM.HNO IN (
                                <foreach collection="hno" item="tmp" separator = ", ">
                                    #{tmp}
                                </foreach>
                                )
                        </if>
                        ORDER BY BNO DESC
                        ) BM
                INNER JOIN BOARD B ON BM.BNO = B.BNO
                INNER JOIN MEMBER M ON M.USERID = B.USERID
                INNER JOIN (SELECT BNO, COUNT(USERID) LIKECOUNT FROM LIKES GROUP BY BNO) R ON R.BNO = B.BNO
                INNER JOIN (SELECT BNO, COUNT(RNO) REPLYCOUNT FROM REPLY GROUP BY BNO) RR ON RR.BNO = B.BNO
                        WHERE (B.TITLE LIKE '%' || #{title} || '%' OR B.CONTENT LIKE '%' || #{content} || '%')
        )
        WHERE ROWN BETWEEN #{page} AND #{page}+11 ORDER BY ROWN
        </select>


3. RestController에서 param값 설정

BoardRestController.java

[ 수정전 ]

게시판 페이지 최초 접속시 데이터를 조회하는 경우
기본값이 필요한 경우 defaultValue 옵션을 지정해주고,
필수로 필요한 값이 아닌 경우 required = false 옵션을 지정해준다

    @GetMapping(value = "/boardselectmain.json")
    public Map<String, Object> boardselectmainGET(
        @RequestParam(name = "hno") List<Long> hno,
        @RequestParam(name = "page", defaultValue = "1") int page,
        @RequestParam(name = "title") String title,
        @RequestParam(name = "content") String content,
        @RequestParam(name = "type") int type,
        HttpServletRequest request
    ) ...

[ 수정후 ]

    @GetMapping(value = "/boardselectmain.json")
    public Map<String, Object> boardselectmainGET(
        @RequestParam(name = "hno", required = false) List<Long> hno,
        @RequestParam(name = "page", defaultValue = "1") int page,
        @RequestParam(name = "title", required = false) String title,
        @RequestParam(name = "content", required = false) String content,
        @RequestParam(name = "type", defaultValue = "1") int type,
        HttpServletRequest request
    )

@RequestParam null값 허용하기

required = false = 필수값이 필요하지 않다

파라미터가 필수값이 아니어도 되는 경우 required = false를 명시해주면
파라미터값에 null이 와도 허용가능하다

RequestParam(value = "id" , required = false) Long id

mybatis 동적 쿼리문

mybatis에서 <choose>, <when>, <otherwise> 구문은
if - else 구문 처럼 사용할 수 있다

참고링크 - [MyBatis] 동적 쿼리

0개의 댓글