https://github.com/simhani1/spring-springboot_with_jpa1
실전! 스프링 부트와 JPA 활용
https://github.com/simhani1/spring-springboot_with_jpa1
Last synced: 12 months ago
JSON representation
실전! 스프링 부트와 JPA 활용
- Host: GitHub
- URL: https://github.com/simhani1/spring-springboot_with_jpa1
- Owner: simhani1
- Created: 2023-01-22T13:41:37.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2023-01-30T08:27:45.000Z (over 3 years ago)
- Last Synced: 2025-04-19T05:26:03.180Z (about 1 year ago)
- Language: Java
- Size: 555 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
실전! 스프링 부트와 JPA 활용
#### gradle 의존관계 확인법
- 터미널로 이동하여 `./gradlew dependecies`를 입력하면 의존관계가 출력된다.
- slf4j: 로그를 찍는 인터페이스 모음이라고 생각하면 된다.
#### 스프링 부트 thymeleaf viewName 자동 매칭
- 스프링 부트는 templates 폴더 내부의 html파일명을 자동으로 매칭시켜준다.
#### 꿀팁!
- `implementation 'org.springframework.boot:spring-boot-devtools'`를 의존성으로 추가하면 html 파일을 `build -> recompile`만 실행해주면 실시간으로 변화를 볼 수 있다.
#### 도메인 주도 개발
**기능 목록**
- 회원 기능
- 회원 등록
- 회원 조회
- 상품 기능
- 상품 등록
- 상품 수정
- 상품 조회
- 주문 기능
- 상품 주문
- 주문 내역 조회
- 주문 취소
- 기타 요구사항
- 상품은 재고 관리가 필요하다.
- 상품의 종류는 도서, 음반, 영화가 있다.
- 상품을 카테고리로 구분할 수 있다.
- 상품 주문시 배송 정보를 입력할 수 있다.

> 참고: 외래키가 있는 곳을 연관관계의 주인으로 정해라
> 외래키가 없는 곳을 주인으로 정하면, 외래키 값이 업데이트 되면서 관리와 유지보수가 어렵고, 추가적으로 별도의 업데이트 쿼리가 발생하는 성능 문제도 있다.
#### 엔티티 개발
- 실무에서는 Setter는 꼭 필요한 경우에만 사용하는 것을 추천한다.
- Setter를 막 열어두면 가까운 미래에 인티티가 왜 변경되는지 추적하기가 힘들어진다.
- 따라서 엔티티를 변경할 때는 Setter 대신에 변경 지점이 명확하도록 변경을 위한 비즈니스 메서드를 별도로 제공해야 한다.
#### 엔티티 설계시 주의점
- 엔티티에는 가급적 setter를 사용하지 말자
- 모든 연관관계는 지연로딩으로 설정
- 즉시로딩은 예측이 어렵고 어떤 SQL이 실행될지 추적하기 어렵다.
- 실무에서 모든 연관관계는 지연로딩으로 설정해야 한다.
- JPQL을 실행할 때 N+1문제가 자주 발생한다.
- 컬렉션은 필드에서 초기화하자
- null문제에서 안전하다
- 하이버네이트는 엔티티를 영속화할 때 컬렉션을 감싸서 하이버네이트가 제공하는 내장 컬렉션으로 변경한다.
- 테이블 칼럼명 생성 전략
#### 단위 테스트
- test와 main의 설정 파일을 구분해서 작동시킬 수 있다.
- 따라서 ApplicationContext.yml파일을 test에도 따로 두고 실행시키는 것이 좋다.
- 이때 DB에 실제로 연결하는 것은 별로 권장하지 않는다.
- Mock객체를 사용하여 테스트를 하면 된다.
- 하지만 스프링 부트는 가짜 메모리 DB를 제공해주기 때문에 따로 설정할 것이 없다.
#### 도메인 모델 패턴
- 주문 서비스의 주문과 주문 취소 메서드를 보면 비즈니스 로직 대부분이 엔티티에 있다.
- 서비스 계층은 단순히 엔티티에 필요한 요청을 위임하는 역할을 한다.
- 이처럼 엔티티가 비즈니스 로직을 가지고 객체 지향의 특성을 적극 활용하는 것을 도메인 모델 패턴이라고 한다.
- 반대로 엔티티에는 비즈니스 로직이 거의 없고 서비스 계층에서 대부분의 비즈니스 로직을 처리하는 것을 드랜잭션 스크립터 패턴이라고 한다.
#### 변경 감지와 병합(merge)
*정말 중요*
- 준영속 엔티티
- 영속성 컨텍스트가 더이상 관리하지 않는 엔티티를 말한다.
- `itemService.saveItem(book)`에서 수정을 시도하는 `Book`객체가 해당된다.
- 해당 객체는 DB에 한번 저장되어서 식별자가 존재한다. 이렇게 임의로 만들어낸 엔티티도 기존 식별자를 가지고 있으면 준영속 엔티티로 볼 수 있다.
- 방법1
- 영속성 컨텍스트에서 엔티티를 다시 조회한 후에 데이터를 수정하는 방법
- 트랜잭션 안에서 엔티티를 다시 조회, 변경할 값 선택 -> 트랜잭션 커밋 시점에 변경 감시가 동작해서 DB에 update sql을 실행한다.
```java
@Transactional
// 변경감지를 사용하여 준영속 엔티티를 수정하는 방법
public void updateItem(Long itemId, Book param) {
Item findItem = itemRepository.findOne(itemId);
findItem.setPrice(param.getPrice());
findItem.setName(param.getName());
findItem.setStockQuantity(param.getStockQuantity());
}
```
- 방법2
- 병합 사용
- 위에서 하는 방식과 동일하다.
```java
public void save(Item item) {
if (item.getId() == null) {
em.persist((item)); // 실제 추가
} else {
em.merge(item); // 업데이트라고 생각을 하자
}
}
```
> **주의사항**
>
> 변경 감지 기능을 사용하면 원하는 속성만 선택해서 값을 변경할 수 있다.
>
> 하지만 병합을 사용하면 모든 속성의 값들이 변경된다. 병합시 값이 없으면 `null`로 업데이트가 될 수도 있으므로 위험하다.
>
> 따라서 머지를 안쓴다고 생각하고 하나하나 변경감지 방법을 사용하도록 작성하는 것이 맞다고 생각해라
- 가장 좋은 방법
- 엔티티를 변경할 때는 항상 변경감지를 사용해라
- 컨트롤러에서 어설프게 엔티티를 생성하지 말고 차라리 DTO 객체, 아에 매개변수로 변경되는 값을 넘기는 방식을 사용하라
- 트랜잭션이 있는 서비스 계층에 식별자와 함께 변경할 데이터를 명확하게 전달해라
- 트랜잭션이 있는 서비스 계층에서 영속 상태의 엔티티를 조회하고, 엔티티의 데이터를 직접 변경해라
- 트랜잭션 커밋 ㅎ시점에 변경 감지가 실행됩니다.