페이징 처리

dawn·2021년 6월 11일
0

TIL

목록 보기
14/14

목표

Oracle로 작성한 쿼리를 Mysql로 바꾸고 테스트 코드를 작성해보자


1. Oracle을 Mysql로

Oracle쿼리 (Mybatis)

<![CDATA[SELECT B.num, B.title, B.writer, B.updatedate
		FROM(
			 SELECT ROWNUM as rn, A.num, A.title, A.writer, A.updatedate 
  			 FROM (
     			   SELECT * FROM board 
     			   WHERE type=#{type} AND title LIKE '%'||#{cri.keyword}||'%' ORDER BY num DESC) A 
     			   
   			  WHERE rownum <=#{cri.pageNum} * #{cri.amount}) B 
		WHERE rn>(#{cri.pageNum}-1) * #{cri.amount}]]>

Mysql

SELECT B.num, B.title, B.writer, B.updatedate FROM(
			SELECT *
			FROM board
			WHERE type='faq'
			order by num asc
		)B
		LIMIT 10,10;
  • LIMIT {OFFSET}, {LIMIT}
    LIMIT 0,10 이면 1번부터 10개 출력해주라는 뜻
    LIMIT 10,10 이면 11부터 10개 출력해달라는 뜻
    따라서 LIMIT (페이지 번호 -1) * ({OFFSET})
    음... OFFSET개수는 Criteria에서 가져올 것이다.

No offset

페이징 검색하다가 커서를 이용하는게 장점이 있다고 해서 이걸로도 구현해봤다. controller까지만..ㅎㅎ
커서로 구현한다길래 정말 "커서"를 사용하는 줄 알고 커서까지 찾아봤는데 다른거였다.

	<select id="getListWithPagingCursor" resultMap="board" parameterType="java.util.HashMap">
		SELECT * FROM board
			WHERE type=#{type}
			AND title LIKE concat('%', #{cri.keyword},'%')
			<if test= "cri.cursorId != null">
		<![CDATA[AND num < #{cri.cursorId}]]>
			</if>
			order by num desc
			LIMIT #{cri.amount}
	</select>

No Offset 테스트 코드

@Test
    @DisplayName("두번째로 조회하는 페이지의 id는 첫번째의 id보다 작다.")
    public void getListWithPagingCursor() {
        //given
        //cursorID가 null일 때(첫번쨰 조회)
        Criteria cri1 = new Criteria();
        HashMap<String, Object> map1 = new HashMap<>();
        map1.put("type", "faq");
        map1.put("cri", cri1);
        List<Board> firstPaging = boardMapper.getListWithPagingCursor(map1);
        
        Integer cursorId = firstPaging.get(9).getNum(); //제일 마지막으로 가져온 id를 cursorId로 설정
        log.info("cursorId: {}", String.valueOf(cursorId));

        //cursorID가 전해질떄(두번쨰 이상 조회)
        Criteria cri2 = new Criteria();
        cri2.setCursorId(cursorId);
        HashMap<String, Object> map2 = new HashMap<>();
        map2.put("type", "faq");
        map2.put("cri", cri2);

        //when
        List<Board> secondPaging = boardMapper.getListWithPagingCursor(map2);

        //then //뭘로 확인하지....
        Assertions.assertThat(secondPaging.get(0).getNum()).isLessThan(firstPaging.get(9).getNum());
    }

뭔가 given/when/then 나누기가 너무 어려운데,,, 테스트 코드를 어떻게 짜야 잘짰다고 소문이 날까...


커서

정말 커서를 쓰는줄 알고 알아본것들ㅎㅎㅎ

  • OPEN, FETCH, CLOSE 문을 사용하여 커서를 제어
  • 커서의 작동 순서
    1. 커서 선언(DECLARE)
    커서는 반드시 사용하기 전에 선언하여야 한다. 이 절차는 실제 어떤 데이터도 가져오진 않고, 단지 사용할 SELECT문과 커서 옵션을 정의한다.
    1. 반복 조건 선언(DECLARE, HANDLER)
    2. 커서 열기(OPEN)
      OPEN CURSOR문이 처리될때 쿼리가 수행되며, 니중에 탐색하거나 가져오기 위해 데이터를 저장한다.
    3. 커서에서 데이터 가져오기(FETCH)
      FETCH는 어떤 행을 가져올지, 어디서부터 가져올지 그리고 어디에 저장할지(예를 들면 변수명 등)를 정의한다.
    4. 데이터 처리
    5. 커서 닫기

MYSQL := 대입연산자

함수와 프로시저

함수는 쿼리를 수행한 후 값을 가져오는 것이 중점이지만
프로시저는 여러 쿼리를 한번에 수행하는 것이 중점이다.

프로시저를 생성하가에 앞서 MYSQL에 프로시저 생성 권한을 줬는지 확인하고 Create Stored Procedure를 눌러 프로시저를 생성해 준다.

CREATE PROCEDURE '[프로시저명]' (
		[파라미터명1] VARCHAR(20) --파라미터 선언
     , [파라미터명2] INTEGER
)
BEGIN
	DECLARE [변수명1] INTEGER --변수명
 
 SELECT COUNT(*) + 1
 	INTO [변수명1] --변수에 값 할당
     FROM [테이블 명];
     
 INSERT INTO [테이블명](NUM, NAME, AGE) VALUES(변수명1, [값], [값])
END

호출하는 방법은 CALL [프로시저명]([파라미터1], [파라미터1]); --프로시저 실행


쿼리 실행 순서

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY

profile
안녕하세요

0개의 댓글