티스토리 뷰
[ 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
'KH 정보교육원 [ Java ]' 카테고리의 다른 글
KH 117일차 - Spring ( 게시판 만들기 - 비지니스 / 프레젠테이션 계층 ) (*****) (0) | 2022.08.12 |
---|---|
KH 116일차 - Spring ( 게시판 만들기 - 영속성 / 비지니스 계층 ) (****) (0) | 2022.08.11 |
KH 114일차 - Spring ( Controller - 예외처리 / 게시판 만들기 ) (*****) (0) | 2022.08.09 |
KH 113일차 - Spring MVC ( 파일 업로드 처리 ) (****) (0) | 2022.08.08 |
KH 112일차 - Spring ( Controller ) (****) (0) | 2022.08.05 |
댓글