비즈니스 계층과 영속성 계층은 웹과는 관련이 없다. = root-context
package org.zerock.myapp.service;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.zerock.myapp.domain.BoardDTO;
import org.zerock.myapp.domain.BoardVO;
import org.zerock.myapp.exception.ServiceException;
public interface BoardService {
// 각 웹 3계층의 성격에 맞게 추상메소드의 이름을 결정하라
// 1. 게시글 전체목록 획득(게시글 번호의 역순으로...)
public abstract List<BoardVO> getList() throws ServiceException;
// 2. 새로운 게시글 등록
public abstract boolean register(BoardDTO dto) throws ServiceException;
// 3. 기존 게시글 수정
public abstract boolean modify(BoardDTO dto) throws ServiceException;
// 4. 기존 게시글 삭제
public abstract boolean remove(BoardDTO dto) throws ServiceException;
//5. 특정 게시글 상세조회
public abstract BoardVO get(BoardDTO dto) throws ServiceException;
}// end interface
(영속성 영역에 BoardMapper 클래스를 이용하는 것을 이해하는 것이 중요)
package org.zerock.myapp.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zerock.myapp.domain.BoardDTO;
import org.zerock.myapp.domain.BoardVO;
import org.zerock.myapp.exception.ServiceException;
import org.zerock.myapp.mapper.BoardMapper;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
@Log4j2
@NoArgsConstructor
// 핵심 비지니스 로직구현
@Service
public class BoardServiceImpl implements BoardService {
@Setter(onMethod_= @Autowired)
private BoardMapper mapper;
@Override
public List<BoardVO> getList() throws ServiceException {
log.trace(" getList() invoked.");
try {
return this.mapper.selectAllList();
} catch (Exception e) {
throw new ServiceException(e);
} // try - catch
}//getList
@Override
public boolean register(BoardDTO dto) throws ServiceException {
log.trace(" register({}) invoked.", dto);
try {
// return this.mapper.insert(dto) == 1;
return this.mapper.insertSelectKey(dto) == 1;
} catch (Exception e) {
throw new ServiceException(e);
} // try - catch
}//register
@Override
public boolean modify(BoardDTO dto) throws ServiceException {
log.trace(" modify({}) invoked.", dto);
try {
return this.mapper.update(dto) == 1;
} catch (Exception e) {
throw new ServiceException(e);
} // try - catch
}//modify
@Override
public boolean remove(BoardDTO dto) throws ServiceException {
log.trace(" remove({}) invoked.", dto);
try {
return this.mapper.delete(dto.getBno()) == 1;
} catch (Exception e) {
throw new ServiceException(e);
} // try - catch
}//remove
@Override
public BoardVO get(BoardDTO dto) throws ServiceException {
log.trace(" get({}) invoked.", dto);
try {
return this.mapper.select(dto);
} catch (Exception e) {
throw new ServiceException(e);
} // try - catch
}//get
}//end class
(어노테이션 사용과 전체적인 흐름만 파악하기 별거없음)
package org.zerock.myapp.service;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.util.List;
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.BoardDTO;
import org.zerock.myapp.domain.BoardVO;
import org.zerock.myapp.exception.ServiceException;
import lombok.Cleanup;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
@Log4j2
@NoArgsConstructor
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = {
"file:src/main/webapp/WEB-INF/**/root-context.xml"
})
@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BoardServiceTests {
@Setter(onMethod_= {@Autowired})
private BoardService service;
@BeforeAll
void beforeAll() {
log.trace("beforeAll() invoked");
assertNotNull(this.service);
log.info("\t + this.service:{}" , this.service);
}// beforeAll
@Test
@Order(1)
@DisplayName("1. BoardService.getlist ")
@Timeout(value = 3 , unit=TimeUnit.SECONDS)
void testGetList() throws ServiceException {
log.trace("testGetList() invoked.");
@Cleanup("clear")
List<BoardVO> list = this.service.getList();
list.forEach(log::info);
}//testGetList
@Test
@Order(2)
@DisplayName("2. BoardService.register ")
@Timeout(value = 3 , unit=TimeUnit.SECONDS)
void testRegister() throws ServiceException {
log.trace("testRegister() invoked.");
BoardDTO dto = new BoardDTO();
dto.setTitle("TITLE_NEW");
dto.setContent("CONTENT_NEW");
dto.setWriter("WRITER_NEW");
log.info("\t + result : {}" , this.service.register(dto));
}//testRegister
@Test
@Order(3)
@DisplayName("3. BoardService.modify ")
@Timeout(value = 3 , unit=TimeUnit.SECONDS)
void testModify() throws ServiceException {
log.trace("testModify() invoked.");
BoardDTO dto = new BoardDTO();
dto.setBno(77);
dto.setTitle("TITLE_UPDATED");
dto.setContent("CONTENT_UPDATED");
dto.setWriter("WRITER_UPDATED");
log.info("\t + result : {}" , this.service.modify(dto));
}//testModify
@Test
@Order(4)
@DisplayName("4. BoardService.remove ")
@Timeout(value = 3 , unit=TimeUnit.SECONDS)
void testRemove() throws ServiceException {
log.trace("testRemove() invoked.");
BoardDTO dto = new BoardDTO();
dto.setBno(77);
log.info("\t + result : {}" , this.service.remove(dto));
}//testRemove
@Test
@Order(5)
@DisplayName("4. BoardService.get ")
@Timeout(value = 3 , unit=TimeUnit.SECONDS)
void testGet() throws ServiceException {
log.trace("testGet() invoked.");
BoardDTO dto = new BoardDTO();
dto.setBno(77);
log.info("\t + BoardVO : {}" , this.service.get(dto));
}//testGet
}//end class
- Oracle Hint 에 대해서 배우자!!!!
(https://devuna.tistory.com/35 여기서 참고)
Syntax: /+ oraclehint /
특징: Oracle Hint 의 문법을 잘못적용해도, SQL 구문 오류가 발생하지는 않습니다.
단지, Oracle Hint 의 효과를 받을 수 없는 게 문제이지요.
그리고 Oracle Hint 는 대소문자를 가리지 않습니다(case-insensitive)
tbl_board table의 PK column => BNO
PK 제약조건이 걸린 컬럼에는 자동으로 Unique Index 가 생성된다!!! (***)
- Oracle Hint 의 종류에 대해서 알아두자!
(1) /*+ index(tablename indexname) */
|| /*+ index(tablename) */
바로 아래의 index_asc 힌트와 같음
(2) /*+ index_asc(tablename indexname) */
|| /*+ index_asc(tablename) */
(3) /*+ index_desc(tablename indexname) */
|| /*+ index_desc(tablename) */
(4) /*+ full(tablename) */
Table Full Scan
(테이블 전체를 순차검색)을 발생시킴(인덱스 전혀 사용하지 않고...)사용
SELECT /*+ full(tbl_board) */ * FROM tbl_board;
- ROW_NUMBER() OAF를 이용한 방법
(https://gent.tistory.com/170 여기에 자세하게 적혀있음)
ROW_NUMBER() 구간내에서 정렬된 순서를 기준으로 반환
SELECT row_number() over(ORDER BY bno DESC) AS ROWN, t.* FROM tbl_board t;
WITH 절은 임시 테이블 또는 가상 테이블(쿼리문 내에서만 실행)
WITH T AS (SELECT row_number() over(ORDER BY bno DESC) AS ROWN, t.* FROM tbl_board t)
모든 컬럼에 대해 T테이블에서 rown조건에 맞춰 77 이상 87 미만의 수를 뽑아라
SELECT * FROM T WHERE rown between 77 AND 87;