본문 바로가기

👩‍💻 BackEnd/📊데이터베이스 [Database]

[일경험 / oracle] 프로시저 활용한 조회수 기능 구현

✅ 프로시저를 구현하게 된 계기 

 

일경험 프로그램에서 게시판 기본적인 기능 구현을 마친 뒤 새로운 기능을 하나 추가하는 과제를 진행하게 되었다. 

 

바로 데이터베이스에서 비즈니스 로직을 수행할 수 있는 프로시저 기능을 활용하여 조회수를 카운트하는 기능이었다. 

 

✅ 프로시저가 뭔가? 

프로시저

  • 프로시저는 PL/SQL 을 통해서 만들어짐.
  • 데이터 베이스 내에서 실행 가능한 저장된 프로그램
  • 프로시저는 SQL 쿼리와 제어구조를 포함할 수 있으며 데이터 베이스의 복잡한 작업을 수행하는 데 사용됨.
  • 프로시저는 코드의 재사용성, 유지 보수성, 성능 향상, 보안 등을 위해 사용됨.

특징

  • 저장된 프로그램 : 프로시저는 데이터베이스 내에 저장. 한 번 작성된 후 여러번 호출할 수 있다.
  • 파라미터로 입력값을 받을 수 있고, 출력값을 반환받을 수 있다.
  • 보안 : 사용자가 직접 쿼리를 작성하지 않고, 미리 정의된 프로시저를 호출함으로써 보안을 강화할 수 있다.

장점

  • 재사용성
  • 유지보수성 : 복잡한 로직을 프로시저로 분류하여 코드의 유지보수를 용이하게 한다.
  • 성능향상 : 데이터베이스 서버에서 실행되므로 네트워크 트래픽을 줄일 수 있다. 컴파일 된 상태로 저장되어 성능이 향상될 수 있음.
  • 보안 : 사용자 권한을 통해 접근을 제어할 수 있음.

간단하게 chat gpt 에게 물어봐서 프로시저가 뭔지 감을 잡았다. 

 

비즈니스 로직을 자바 코드로 짜지 않고도 프로시저를 활용해서 직접 데이터베이스의 값을 업데이트하고 생성할 수 있다니! 

아주 편리한 기능이라는 것을 알 수 있었다. 

 

그리고 팀장님이나 다른 인턴분들과 대화해본 결과 프로시저는 현업에서 엄청 많이 사용되고 내가 짠 쿼리는 너무 짧은 편에 속하고 현업에서는 프로시저가 엄청 많을 것이라고 해주셨다. 

 

두근두근!! 

 

정보처리기사 공부를 할 때 항상 들었던 기능인데 이번 기회에 직접 작성하고 활용해볼 수 있어 매우 흥미로웠다! 

 

✅ 내가 작성한 조회 수 증가 프로시저 코드 

 

 

CREATE OR REPLACE PROCEDURE BASIC.MHBOARD_COUNT_PROC
(

    P_BOARD_NO IN NUMBER
   -- 이부분은 결과값을 sql developer 콘솔로 결과를 확인하기 위해 작성한 부분이었기에 주석 처리
   -- P_RESULT OUT VARCHAR
) 
IS
    P_EXIST_CHK NUMBER(2) := 0; 
     
BEGIN 
    SELECT COUNT(*) INTO P_EXIST_CHK FROM VIEWS_MHBOARD WHERE BOARD_NO = P_BOARD_NO;

    IF P_EXIST_CHK  = 0  THEN
    
        INSERT INTO VIEWS_MHBOARD 
        VALUES (P_BOARD_NO, 0);
   --     P_RESULT :='INSERT';
        
    ELSE    
    
        UPDATE VIEWS_MHBOARD
        SET VIEWS = VIEWS + 1
        WHERE BOARD_NO = P_BOARD_NO;
    --    P_RESULT :='UPDATE';
   
    END IF;
   COMMIT;
    
P_EXIST_CHK:=1;

EXCEPTION
    WHEN NO_DATA_FOUND THEN 
        DBMS_OUTPUT.PUT_LINE('NO DATA BOARD_NO: ' || P_BOARD_NO); 

    WHEN OTHERS THEN 
        DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLERRM);
        RAISE;
        
END MHBOARD_COUNT_PROC;

 

 

CREATE OR REPLACE PROCEDURE BASIC.MHBOARD_COUNT_PROC
(
	-- 파라미터로 받을 부분 선언 : 게시글의 번호를 파라미터로 받을 예정 
    -- IN NUMBER는 파라미터의 타입을 지정
    -- IN 은 입력 받을 파라미터 
    P_BOARD_NO IN NUMBER
    
   -- 이부분은 결과값을 sql developer 콘솔로 결과를 확인하기 위해 작성한 부분이었기에 주석 처리
   -- OUT 은 결과값을 리턴받을 파라미터 
   -- P_RESULT OUT VARCHAR
) 
IS
	-- 활용할 변수를 선언하는 곳 
    -- 나는 P_EXIST_CHK 라는 변수에 이미 존재하는지 여부를 확인한 결과를 담기 위해 선언, 기본값은 0
    P_EXIST_CHK NUMBER(2) := 0; 
     
BEGIN 
	-- view_mhboard 테이블에서 파라미터로 입력받은 게시글의 번호랑 일치하는 게시글 번호가 있는지 조회 
    -- 있으면 그 수를 count 라는 집계함수로 개수로 조회 
    SELECT COUNT(*) INTO P_EXIST_CHK FROM VIEWS_MHBOARD WHERE BOARD_NO = P_BOARD_NO;

	-- 입력받은 파라미터인 게시글 번호와 일치하는 게시글 번호가 없을 경우, 
    -- 즉, 조회수 카운트하는 테이블에 게시글 번호가 존재하지 않을 경우 
    IF P_EXIST_CHK  = 0  THEN
    
    -- 게시글 조회 테이블에 게시글 번호와 조회수를 1로 설정하여 데이터를 insert 한다
        INSERT INTO VIEWS_MHBOARD 
        VALUES (P_BOARD_NO, 1);
   -- 만약 해당 insert 쿼리를 수행한 경우, OUT으로 설정했으니 콘솔에 INSERT 라는 글자를 출력 
   --     P_RESULT :='INSERT';
        
    ELSE    
    -- 그 반대의 경우 즉, 이미 게시글 조회 테이블에 파라미터로 입력받은 게시글 번호와 동일한 글이 존재할 경우,
    -- 기존의 views 값에  +1 을 하기 
        UPDATE VIEWS_MHBOARD
        SET VIEWS = VIEWS + 1
        WHERE BOARD_NO = P_BOARD_NO;
    --    P_RESULT :='UPDATE';
   
    END IF;
   COMMIT;
    
P_EXIST_CHK:=1;

-- 예외처리 부분 
EXCEPTION
	-- 데이터가 존재하지 않을 경우 다음과 같은 글자를 콘솔에 출력하기  
    WHEN NO_DATA_FOUND THEN 
        DBMS_OUTPUT.PUT_LINE('NO DATA BOARD_NO: ' || P_BOARD_NO); 

    WHEN OTHERS THEN 
        DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLERRM);
        RAISE;
        
END MHBOARD_COUNT_PROC;

 

다음과 같이 게시글을 조회 기능 프로시저를 생성했다. 

 

그리고 이제는 이 프로시저를 호출해서 조회수가 정상적으로 올라가는지 확인을 해야한다. 

 

Controller 
// controller 에서 조회수를 증가 시키는 서비스 로직 호출
mhBoardService.boardViewCnt(Integer.valueOf(boardNo));

 

Service 
// 게시글 조회 수 올리는 메서드
public void boardViewCnt(int boardNo) {
    mhBoardMapper.boardViewCnt(boardNo);
}

 

✅ Mybatis mapper.xml 파일에서 작성한 프로시저 호출 코드 
<select id="boardViewCnt" statementType="CALLABLE">
    {CALL MHBOARD_COUNT_PROC(#{boardNo})}
</select>

 

 

✅ 게시판 메인 페이지에서 조회 수를 카운트 해오는 mapper.xml 파일의 쿼리 
<select id="selectAllBoardList">
	<![CDATA[
	SELECT RN, BOARD_NO, BOARD_UPDATE, BOARD_TITLE, USER_NAME, views
        FROM(
            SELECT rownum rn, board_no, board_update, board_title, user_name, views
                FROM(
                    SELECT a.board_no ,a.board_update ,a.board_title,b.user_name, c.views
                    FROM USER_MHBOARD a 
                    LEFT OUTER JOIN user_info b
                        ON b.user_no = a.user_no
                    LEFT OUTER JOIN VIEWS_MHBOARD c
                        ON a.board_no = c.board_no
                    WHERE a.board_show = 'Y'
                    order by BOARD_NO DESC
                    )
            )
        WHERE rn BETWEEN (#{pageCnt}-1)*10 + 1 and #{pageCnt}*10
	]]>
</select>

 

 

하지만 여기서 한번 더 생각해야할 부분이 있다. 

조회 수를 누를 때 마다 카운트를 하는 것은 임의로 사용자가 계속해서 카운트를 해서 조작할 수 있게 된다. 

 

사실 아직은 작은 개인 프로젝트이긴 하지만 

이런 부분도 함께 처리를 해주는 것이 조금 더 정확한 조회수를 얻기에 적합하다고 생각한다. 

 

중복된 조회 수 증가를 막기 위해서 나는 브라우저 쿠키에 해당 사용자가 브라우저에서 해당 게시글을 방문한 적이 있는지 담아주기로 했다.

 

쿠키에 사용자가 조회한 게시글의 번호를 기록하여 남겨주는 방식인데

여기서 한번 더 고민한 것이 게시글을 클릭할 때마다 하나의 쿠키를 발행하는 것은 쿠키의 낭비라고 생각한다! 

 

따라서 검색을 열심히 해본 결과 하나의 쿠키에 여러 개의 게시글의 번호를 누적해서 저장하고 이를 확인하는 방법을 찾아냈다. 

 

이 글은 다음편에 계속 작성해보아야겠다!