티스토리 뷰

 

[ 1. ROWNUM / ROW_NUMBER ] (*)

 


[ 2. TOP-N Query ( 상위 N개의 행을 출력하는 쿼리 ) ] (***)

 

더보기

[ + 코드 보기 ]

-- ----------------------------------------------
-- 1. Top-N Query ( 상위 N개만 추출하는 쿼리 )
-- ----------------------------------------------
-- + 우리가 1 페이지에 10개 씩만 보여주게 하려고 할 때,
-- + 상위 10개씩 끊어야 하는데, 이때 사용한다.
-- ----------------------------------------------

-- ----------------------------------------------
-- + rownum 사용하지 않는 버전 (****)
-- ----------------------------------------------

-- + ONLY는 지정된 행만 출력한다. ( 중복을 신경쓰지 x )
-- + FIRST 뒤에 숫자를 넣어 상위 몇개를 출력할 수 있다.
SELECT bno, val
FROM tbl_test
ORDER BY bno DESC
FETCH FIRST ROWS ONLY;

-- + WITH TIES는 첫번째 행과 같은 행이 여러개이면 같이 출력해 준다.
-- + 중복된 행까지 같이 출력해 준다.
SELECT bno, val
FROM tbl_test
ORDER BY bno DESC
FETCH FIRST ROWS WITH TIES;

-- + &v_rows를 입력해 주면 몇 개의 행을 출력할지 입력창이 나타난다. (***)
-- + 10을 입력해 주면, 상위 10개를 출력해 준다.
-- + FETCH FIRST &v_rows ROWS WITH TIES;도 가능하다.
SELECT bno, val
FROM tbl_test
ORDER BY bno DESC
FETCH FIRST &v_rows ROWS ONLY;

-- + &v_percent를 입력해 주면 상위 몇 %의 행들을 출력할 수 있다. (***)
-- + &v_rows와 마찬가지로 입력창이 나타나며, 10을 입력하면 상위 10%가 출력된다.
-- + FETCH FIRST &v_percent PERCENT ROWS WITH TIES;도 가능하다.
SELECT bno, val
FROM tbl_test
ORDER BY bno DESC
FETCH FIRST &v_percent PERCENT ROWS ONLY;

[ 3. OFFSET( 몇 번째 행부터 가져오라! ) ] (***)

 

더보기

[ + 코드 보기 ]

-- ----------------------------------------------
-- + OFFSET 사용 버전 ( OFFSET으로 시작 행을 선택할 수 있다. ) (***)
-- ----------------------------------------------

-- + &v_offset를 입력하면, 몇 번째 행부터 시작할지 입력창이 나타나며,
-- + 지정된 행부터 &v_length의 입력창에 입력된 행만큼 추출할 수 있다.
-- + 단 &v_offset에 지정된 행은 포함되지 않는다.
-- + 즉, &v_offset에서 3을 입력하면 4번째부터 포함되어 카운팅된다.
-- + 이때는 NEXT를 사용하게 된다.

SELECT bno, val
FROM tbl_test
OFFSET &v_offset ROW            -- 지정된 행부터
FETCH NEXT &v_length ROWS ONLY  -- 몇 개의 레코드를 추출해라

[ 4. OFFSET / FETCH 실습 ] (***)

 

더보기

[ + 코드 보기 ]

-- ----------------------------------------------
-- + OFFSET / FETCH 실습
-- ----------------------------------------------

-- + HR 계정에서 2번째 부터 5개의 국가 추출하기
-- + OFFSET에 지정된 수의 행은 포함되지 않기에, 1을 지정해줘야 2번째부터 출력이 가능하다.
SELECT *
FROM countries
OFFSET 1 ROW
FETCH NEXT 5 ROWS ONLY;

-- + HR 계정에서 1번째 국가부터 총 3개의 국가 추출하기
SELECT *
FROM countries
FETCH FIRST 3 ROWS ONLY;

-- + HR계정에서 5번째 국가부터 총 10개의 국가를 추출하기
SELECT *
FROM countries
OFFSET 4 ROW
FETCH NEXT 10 ROWS ONLY;

-- + HR계정에서 12번째 국가부터 총 30개의 국가를 추출하기
-- + HR계정의 countries 테이블에서는 총 26개의 행밖에 없기에 범위를 넘어간 상태이다.
-- + FETCH절에서 오버된 행을 출력하라고 해도, 테이블에 맞는 행만 추출하게 된다. (**)
SELECT *
FROM countries
OFFSET 11 ROW
FETCH NEXT 30 ROWS ONLY;

-- + HR계정에서 17번째 국가부터 마지막 국가까지 추출하기 1
-- + OFFSET만 지정하고 FETCH를 지정하지 않으면, 지정한 번째부터 끝까지 출력한다.
SELECT *
FROM countries
OFFSET 16 ROW;

-- + HR계정에서 17번째 국가부터 마지막 국가까지 추출하기 2
SELECT *
FROM countries
OFFSET 16 ROW
FETCH NEXT 100 percent ROWS ONLY;

[ 5. 게시판 만들기 ] (****)

 

[ 5 - 1. VO 만들기 - BoardVO ]

 

더보기

[ + 코드 보기 ]

package org.zerock.myapp.domain;

import lombok.Value;


@Value
public class BoardVO {
	
	private Integer bno;
	private String title;
	private String content;
	private String writer;

} // end class

 

[ 5 - 2. Servlet-context.xml파일에서 Mapper 등록 ]

 

더보기

[ + 코드 보기 ] 

<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- < resources mapping location >의 경우 파일을 생성하여 매핑할 수 있으며, 같은 location이여도 mapping을 추가할 수 있다. -->
	<!-- 아래의 태그로 인해 URL mapping처럼 http://localhost:8080/resources/파일명으로 접근이 가능하다. -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- [ 현재 버전 ] -->
	<!-- View Resolver -->
	<view-resolvers>
		<jsp prefix="/WEB-INF/views/" suffix=".jsp" />
	</view-resolvers>

	<!-- 파일 업로드 -->
	<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<beans:property name="defaultEncoding" value="utf8" />
		<!-- 최대 10mb까지 업로드 가능 -->
		<beans:property name="maxInMemorySize" value="10485760" />
		<beans:property name="maxUploadSize" value="10485760" />
		<!-- 파일 1개당 최대 사이즈는 2mb로 제한 -->
		<beans:property name="maxUploadSizePerFile" value="2097152" />
		<!-- 파일의 이름을 저장할지 지정 -->
		<beans:property name="preserveFilename" value="true" />
		<!-- 업로드할 정소 지정 -->
		<!-- 로컬에서는 경로를 file:///로 시작해야 한다. -->
		<!-- multipartResolver 빈에서는 임시폴더를 지정해야 하기에 Temp까지만 지정해 준다. -->
		<beans:property name="uploadTempDir" value="file:///C:/Temp/" />
	</beans:bean>

	<!-- base-package에 작성한 패키지 내에 있는 것을 빈으로 등록시킨다. -->
	<context:component-scan base-package="org.zerock.myapp.controller" />

	<!-- <context:component-scan base-package="org.zerock.myapp.mapper" /> -->
	<mybatis-spring:scan base-package="org.zerock.myapp.mapper" />

	<context:component-scan base-package="org.zerock.myapp.exception" />
	
</beans:beans>

 

[ 5 - 3. 예외 클래스 생성하기 ]

 

더보기

[ + 코드 보기 ]

package org.zerock.myapp.exception;


// + 영속성 계층의 모든 종류의 DAO 구현에서 발생하는 예외를 의미
public class DAOException extends Exception {
	private static final long serialVersionUID = 1L;

	public DAOException(String message) {
		super(message);
	} // constructor
	
	public DAOException(Exception e) {
		super(e);
	} //constructor

} // end class

 

[ 5 - 4. Mapper( interface ) 생성 + 오라클 힌트 ]

 

더보기

[ + 코드 보기 ]

package org.zerock.myapp.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.zerock.myapp.domain.BoardVO;
import org.zerock.myapp.exception.DAOException;

// + 이 자바 인터페이스가 영속성 계층의 DAO 역할을 할
// + 마이바티스의 Mapper Interface로서의 역할을 하도록 구현
// + Mapper에서 CRUD하게 해준다. (***)
public interface BoardMapper {
	
	// ====================================================================
	// + 1. 게시물 전체 목록 출력하기
	// ====================================================================
	
	// + /*+ index_desc( 테이블명 indexName ) */는 오라클 힌트로 원래는 indexName을 지정해줘야 하지만,
	// + 지정해주지 않으면 테이블(tbl_board)의 PK를 기준으로 desc 내림차순으로 정렬해준다.
	// + INDEX (INDEX_ASC) : 오름차순 정렬, INDEX_DESC : 내림차순 정렬
	// + 같은 기능으로 ORDER BY가 있지만, 시스템에 부담이 되는 기능이기에 사용을 지양해줘야 한다.
	@Select("SELECT /*+ index_desc(tbl_board) */ * FROM tbl_board WHERE bno > 0")
	public abstract List<BoardVO> selectAllList() throws DAOException;
	
	// ====================================================================
	// + 2. 새로운 게시물 등록 -> Mapper XMl
	// ====================================================================
	// + 게시물 등록에 필요한 데이터가 VO 객체로 들어왔기 때문에,
	// + @Param(바인드 변수명) 어노테이션과 @Insert(SQL문) 어노테이션으로 처리가 힘들다.
	// + 그렇기에 Mapper XML 파일에 SQL을 등록해서 처리하는 것이 좋다.
	// ====================================================================
	
	// @Insert("INSERT INTO tbl_board (bno, title, content, writer) VALUES ( ?, ?, ?, ? )")
	public abstract int insert(BoardVO vo) throws DAOException; // insert
	
	// ====================================================================
	// + 3. 게시물 삭제 -> @Delete + @Param ( #{ 바인드변수명 } )
	// ====================================================================
	// + Integer bno -> @Param("bno") -> #{bno}순으로 값이 전달된다.
	// ====================================================================
	
	@Delete("DELETE FROM tbl_board WHERE bno = #{bno}")
	public abstract int delete(@Param("bno")Integer bno) throws DAOException;

} // end interface

 

[ 5 - 5.  Test하기 ]

 

더보기

[ + 코드 보기 ]

package org.zerock.myapp.mapper;

import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.zerock.myapp.domain.BoardVO;
import org.zerock.myapp.exception.DAOException;

import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;

@Log4j2
@NoArgsConstructor

// JUNIT 5
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = { 
						"file:src/main/webapp/WEB-INF/spring/root-context.xml",
						"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})

@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BoardMapperTests {
	
	// @Autowired
	@Setter(onMethod_= {@Autowired})
	private BoardMapper mapper;
	
	@BeforeAll
	void beforeAll() {
		log.trace("beforeAll() invoked.");
		
		assertNotNull(this.mapper);
		log.info("\t + 1. this.mapper : {}", this.mapper);
		// + 1. this.mapper : org.apache.ibatis.binding.MapperProxy@2616b618
		log.info("\t + 2. type : {}", this.mapper.getClass().getName());
		// + 2. type : com.sun.proxy.$Proxy48
		
	} // beforeAll
	
	@Test
	@Order(1)
	@DisplayName("1. BoardMapper.getList() test")
	@Timeout(value=5, unit = TimeUnit.SECONDS)
	void testGetList() throws DAOException {
		
		log.trace("testGetList() invoked.");
		
		List<BoardVO> list = this.mapper.selectAllList();
		// + 오라클 힌트로 내림차순하였기에, PK를 기준으로 내림차순 정렬된다.
		// + mapper에 있는 @Select가 실행된다.
		
		Objects.requireNonNull(list);
		list.forEach(log::info);
		
	} //testGetList
	
	@Test
	@Order(2)
	@DisplayName("2. BoardMapper.testDelete() test")
	@Timeout(value=5, unit = TimeUnit.SECONDS)
	void testDelete() throws DAOException {
			
		log.trace("testDelete() invoked.");
		
		int bno = 30;
		
		int affectedLines = this.mapper.delete(bno);
		log.info("\t + affectedLines : {}", affectedLines);
		assert affectedLines == 1;
		
	} //testGetList

} // end class

 

728x90
댓글
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
최근에 올라온 글
Total
Today
Yesterday
공지사항