[스프링 DB 2편] #1. 데이터 접근 기술 - 시작 #531
Develop-KIM
started this conversation in
동환
Replies: 2 comments
-
|
고생하셨습니다~ |
Beta Was this translation helpful? Give feedback.
0 replies
-
|
수고하셨습니다 DB 2편 가즈아! |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
데이터 접근 기술 진행 방식 소개
적용 데이터 접근 기술
SQLMapper
ORM 관련 기술
개발자는 저장하고 싶은 객체를 마치 자바 컬렉션에 저장하고 조회하듯이 사용하면 ORM 기술이 데이터베이스에 해당 객체를 저장하고 조회해준다.
자바에서 ORM을 사용할 때는 JPA 인터페이스를 사용하고, 그 구현체로 하이버네이트를 사용한다고 생각하면 된다.
실무에서는 JPA를 사용하면 이 프로젝트도 함께 사용하는 것이 좋다.
프로젝트 구조 설명1 - 기본
스프링 부트 3.0
프로젝트 설정
build.gradle
spring-boot-starter-thymeleaf: 타임리프 사용spring-boot-starter-web: 스프링 웹, MVC 기능 사용spring-boot-starter-test: 스프링이 제공하는 테스트 기능lombok: lombok을 추가로 테스트에서도 사용하는 설정도메인 분석
Item
Item은 상품 자체를 나타내는 객체이고 이름, 가격, 수량을 속성으로 가지고 있다.리포지토리 분석
ItemRepositroy 인터페이스
ItemSearchCond
like검색)ItemUpdateDto
DTO(data transfer object)
MemoryItemRepository
ItemRepository인터페이스를 구현한 메모리 저장소이다.findById는Optional을 반환해야 하기 때문에Optional.ofNullable을 사용했다.findAll은ItemSearchCond이라는 검색 조건을 받아서 내부에서 데이터를 검색하는 기능을 한다.데이터베이스로 보면
where구문을 사용해서 필요한 데이터를 필터링 하는 과정을 거치는 것이다.- 자바 스트림을 사용하였다.
-
itemName이나,maxPrice가null이거나 비었으면 해당 조건을 무시한다.-
itemName이나,maxPrice에 값이 있을 때만 해당 조건으로 필터링 기능을 수행한다.clearStore()메모리에 저장된Item을 모두 삭제해서 초기화한다. 테스트 용도로만 사용한다.서비스 분석
ItemService 인터페이스
- 여기서는 예제 설명 과정에서 구현체를 변경할 예정이어서 인터페이스를 도입했다.
ItemServiceV1
컨트롤러 분석
HomeController
ItemController
프로젝트 구조 설명2 - 설정
스프링 부트 설정 분석
MemoryConfig
-
ItemServiceV1,MemoryItemRepository를 스프링 빈으로 등록하고 생성자를 통해 의존관계를 주입한다.TestDataInit
- 이 기능이 없으면 서버를 실행할 때 마다 데이터를 입력해야 리스트에 나타난다. (메모리여서 서버를 내리면데이터가 제거된다.)
@EventListener(ApplicationReadyEvent.class): 스프링 컨테이너가 완전히 초기화를 다 끝내고 실행 준비가 되었을 때 발생하는 이벤트이다.스프링이 이 시점에 해당 애노테이션이 붙은
initData()메서드를 호출해준다.- 참고로 이 기능 대신
@PostConstruct를 사용할 경우 AOP 같은 부분이 아직 다 처리되지 않은 시점에 호출될 수 있기 때문에간혹 문제가 발생할 수 있다. 예를 들어서
@Transactional과 관련된 AOP가 적용되지 않은 상태로 호출될 수 있다.-
@EventListener(ApplicationReadyEvent.class)는 AOP를 포함한 스프링 컨테이너가완전히 초기화 된 이후에 호출되기 때문에 이런 문제가 발생하지 않는다.
ItemServiceApplication
@Import(MemoryConfig.class): 앞서 설정한MemoryConfig를 설정 파일로 사용한다.scanBasePackages = "hello.itemservice.web": 여기서는 컨트롤러만 컴포넌트 스캔을 사용하고 나머지는 직접 수동 등록한다.그래서 컴포넌트 스캔 경로를
hello.itemservice.web하위로 지정했다.@Profile("local"): 특정 프로필의 경우에만 해당 스프링 빈을 등록한다. 여기서는local이라는 이름의 프로필이 사용되는 경우에만testDataInit이라는 스프링 빈을 등록한다. 이 빈은 앞서 본 것인데, 편의상 초기 데이터를 만들어서 저장하는 빈이다.프로필
스프링은 로딩 시점에
application.properties의spring.profiles.active속성을 읽어서 프로필로 사용한다.이 프로필은 로컬(나의 PC), 운영 환경, 테스트 실행 등등 다양한 환경에 따라서 다른 설정을 할 때 사용하는 정보이다.
예를 들어서 로컬PC에서는 로컬 PC에 설치된 데이터베이스에 접근해야 하고, 운영 환경에서는 운영 데이터베이스에
접근해야 한다면 서로 설정 정보가 달라야 한다. 심지어 환경에 따라서 다른 스프링 빈을 등록해야 할 수 도 있다.
프로필을 사용하면 이런 문제를 깔끔하게 해결할 수 있다.
main 프로필
/src/main/resources하위의application.propertiesspring.profiles.active=localapplication.properties는/src/main하위의 자바 객체를 실행할 때 (주로main()) 동작하는 스프링 설정이다.spring.profiles.active=local이라고 하면 스프링은local이라는 프로필로 동작한다.따라서 직전에 설명한
@Profile("local")가 동작하고testDataInit가 스프링 빈으로 등록된다.실행 로그
프로필을 지정하지 않으면 디폴트 프로필이 실행
test 프로필
/src/test/resources하위의application.propertiesspring.profiles.active=testapplication.properties는/src/test하위의 자바 객체를 실행할 때 동작하는 스프링 설정이다.spring.profiles.active=test로 설정하면 스프링은test라는 프로필로 동작한다. 이 경우 직전에 설명한@Profile("local")는 프로필 정보가맞지 않아서 동작하지 않는다. 따라서
testDataInit이라는 스프링 빈도 등록되지 않고, 초기 데이터도 추가하지 않는다.실행 로그
local)에서 직접 실행할 때는testDataInit이 스프링 빈으로 등록된다.따라서 등록한 초기화 데이터를 편리하게 확인할 수 있다.
예를 들어서 데이터를 하나 저장하고 전체 카운트를 확인하는데 1이 아니라
testDataInit때문에 데이터가 2건 추가되어서 3이 되는 것이다.test프로필이 실행된다. 따라서TestDataInit는 스프링 빈으로 추가되지 않고따라서 초기 데이터도 추가되지 않는다.
프로젝트 구조 설명3 - 테스트
ItemRepositoryTest
afterEach(): 테스트는 서로 영향을 주면 안된다. 따라서 각각의 테스트가 끝나고 나면 저장한 데이터를 제거해야 한다.@AfterEach는 각각의 테스트의 실행이 끝나는 시점에 호출된다.여기서는 메모리 저장소를 완전히 삭제해서 다음 테스트에 영향을 주지 않도록 초기화 한다.
clearStore()가 없기 때문에MemoryItemRepository인 경우에만 다운 케스팅을 해서 데이터를 초기화한다.실제 DB를 사용하는 경우에는 테스트가 끝난 후에 트랜잭션을 롤백해서 데이터를 초기화 할 수 있다.
save()updateItem()findItems()null조건도 있지만, 빈 문자("")의 경우에도 잘 동작하는지 검증한다.데이터베이스 테이블 생성
H2
Item테이블 생성쿼리generated by default as identity-
identity전략이라고 하는데, 기본 키 생성을 데이터베이스에 위임하는 방법이다. MySQL의 AutoIncrement와 같은 방법이다.- 여기서 PK로 사용되는
id는 개발자가 직접 지정하는 것이 아니라 비워두고 저장하면 된다.그러면 데이터베이스가 순서대로 증가하는 값을 사용해서 넣어준다.
등록 쿼리
조회 쿼리
참고 - 권장하는 식별자 선택 전략
데이터베이스 기본 키는 다음 3가지 조건을 모두 만족해야 한다.
null값은 허용하지 않는다.테이블의 기본 키를 선택하는 전략은 크게 2가지가 있다.
자연 키보다는 대리 키를 권장한다
자연 키와 대리 키는 일장 일단이 있지만 될 수 있으면 대리 키의 사용을 권장한다. 예를 들어 자연 키인 전화번호를 기본 키로 선택한다면
그 번호가 유일할 수는 있지만, 전화번호가 없을 수도 있고 전화번호가 변경될 수도 있다. 따라서 기본 키로 적당하지 않다.
문제는 주민등록번호처럼 그럴듯하게 보이는 값이다. 이 값은
null이 아니고 유일하며 변하지 않는다는 3가지 조건을 모두 만족하는 것 같다.하지만 현실과 비즈니스 규칙은 생각보다 쉽게 변한다. 주민등록번호 조차도 여러 가지 이유로 변경될 수 있다.
Beta Was this translation helpful? Give feedback.
All reactions