(spring)(실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발_01)

전성영·2022년 7월 6일
0

spring

목록 보기
17/31

새로운 강의는 늘 설레는 거 같다. 파이팅!!!!


설계 단계



복습하면서 정리

  • 1.
    @Embeddable -valueClass 안에
    @Enumerated(EnumType.STRING) - valueClass 쓰는 곳에
    private DeliveryStatus status; // READY, COMP
    한쪽만 써도 된다.
  • 2.
    Enum타입을 사용할 때 - @Enumerated(EnumType.STRING)
    Ordinal 도 있는데, 수정될 때 장애가 난다.
  • 3.
    N:M은 실무에서는 쓰면 안된다!
@ManyToMany
@JoinTable(name="category_item",                        //중간 테이블 매핑
     joinColumns = @JoinColumn(name="category_id"),     //중간 테이블에 있는 내 아이디
     inverseJoinColumns = @JoinColumn(name="item_id"))  //중간 테이블에 있는 상대방 아이디
private List<Item>items = new ArrayList<>();

Category.java

@ManyToMany(mappedBy = "items")
private List<Catrgory>catrgories = new ArrayList<>();

Item.java

  • 4.
    자기참조
    @ManyToOne
    @JoinColumn(name="parent_id")
    private Catrgory parent;
    @OneToMany(mappedBy = "parent")
    private List<Catrgory>child = new ArrayList<>();

참고 : 값 타입은 변경 불가능하게 설계해야 한다.

@Setter 를 제거하고, 생성자에서 값을 모두 초기화해서 변경 불가능한 클래스를 만들자.
JPA 스펙상 엔티티나 임베디드 타입( @Embeddable )은 자바 기본 생성자(default constructor)를 public 또는 protected 로 설정해야 한다.
public 으로 두는 것 보다는 protected 로 설정하는 것이 그나마 더 안전하다.
JPA가 이런 제약을 두는 이유는 JPA 구현 라이브러리가 객체를 생성할 때 리플랙션 같은 기술을 사용할 수 있도록 지원해야 하기 때문이다.


엔티티 설계시 주의점!

  • 엔티티에는 가급적 Setter를 사용하지 말자

    변경 포인트가 너무 많아서, 유지보수가 어렵다.
    나중에 리펙토링으로 Setter를 제거하도록 하자.

  • 모든 연관관계는 지연로딩으로 설정하자

    즉시로딩( EAGER )은 예측이 어렵고, 어떤 SQL이 실행될지 추적하기 어렵다.
    특히 JPQL을 실행할 때 N+1 문제가 자주 발생한다.
    실무에서 모든 연관관계는 지연로딩( LAZY )으로 설정해야 한다.
    연관된 엔티티를 함께 DB에서 조회해야 하면, fetch join 또는 엔티티 그래프 기능을 사용한다.
    @XToOne(OneToOne, ManyToOne) 관계는 기본이 즉시로딩이므로 직접 지연로딩으로 설정해야 한다.

  • 컬렉션은 필드에서 초기화 하자.

    컬렉션은 필드에서 바로 초기화 하는 것이 안전하다.
    ex) private List<Order> orders = new ArrayList<>();
    하이버네이트는 엔티티를 영속화 할 때, 컬랙션을 감싸서 하이버네이트가 제공하는 내장 컬렉션으로 변경한다.
    만약 getOrders() 처럼 임의의 메서드에서 컬력션을 잘못 생성하면 하이버네이트 내부 메커니즘에 문제가 발생할 수 있다.
    따라서 필드레벨에서 생성하는 것이 가장 안전하고, 코드도 간결하다

구현 단계

  • @Transactional(readOnly = true) - 읽기 단계에서 사용하면 최적화가 가능하다.
    **기본값은 false이다

  • TestCode 작성 중

@Runwith 과 @SpringBootTest가 있어야 테스트를 할 수 있다. JUnit4 버전은 그런듯??? 5를 사용했을 때에는 @SpringBootTest만 사용했었다.

또한 기본적으로 @Transactional 하면 Rollback이라 insert문이 나가지 않는다.
쿼리문을 보고싶다면 @Rollback(false) 해주기!!


@Test(expected = IllegalArgumentException.class)

이거 꿀팁인 거 같다. Illegal~~ 에러가 터지면 담기는 것. 꿀인 거 같다.


  • 값 변경
    값을 변경할 때 settet로 막 service단에서 하지말고, 클래스에서 비즈니스 로직을 만들자.
    ex)
public void addStock(int quantity){
    this.stockQuantity += quantity;
}

이런식으로!!


@NoArgsConstructor(access = AccessLevel.PROTECTED)
protected 생성자 역할을 한다.


@PostMapping("/members/new")
public String create(@Valid MemberForm form , BindingResult result){
     Address address = new Address(form.getCity(), form.getStreet(), form.getZipcode());

     if(result.hasErrors()){
         return "members/createMemberForm";
     }

     Member member = new Member();
     member.setName(form.getName());
     member.setAddress(address);

     memberService.join(member);
     return "redirect:/";
}

키워드 - @Valid, @NotEmpty, BindingResult, result.hasErrors()
참고 - https://jj-yi.tistory.com/23


변경 감지와 병합(merge)

준영속 엔티티란?

영속성 컨텍스트가 더는 관리하지 않는 엔티티를 말한다.

  • 여기서는 itemService.saveItem(book) 에서 수정을 시도하는 Book 객체다. Book 객체는 이미 DB 에 한번 저장되어서 식별자가 존재한다.
  • 이렇게 임의로 만들어낸 엔티티도 기존 식별자를 가지고 있으면 준영속 엔티티로 볼 수 있다.

준영속 엔티티를 수정하는 2가지 방법

  • 변경 감지 기능 사용
  • 병합(merge) 사용

변경 감지 - 영속성 컨텍스트에서 엔티티를 다시 조회해서 영속성 컨텍스트에 올려놓은 후 데이터를 수정하는 것이다.

병합(merge) - 준영속 엔티티의 식별자 값으로 1차 캐시에 먼저 조회를 한다.
없다면 DB에서 값을 가져와서 조회한 영속 엔티티에 DB에서 가져온 값을 채워 넣는다. 아래의 그림과 코드를 참고하면 이해하기가 쉽다.

@Transactional
public Item updateItem(Long itemId, Book param){
    Item findItem = itemRepository.findOne(itemId);
    findItem.setPrice(param.getPrice());
    findItem.setName(param.getName());
    findItem.setStockQuantity(param.getStockQuantity());
    
    return findItem;
    }

BUT!!
merge는 모든 속성이 변경된다.
즉 여러개의 필드 중 하나의 필드만 빼고 바꾼다고 가정하자.
그럼 그 하나는 null이 되고 db에도 null이 저장된다. 위험위험몬~


setter를 지양해야 하는 이유!
역추적이 불가능하다.
의미있는 메서드를 만들어 두면 역추적이 가능하다!!!

다음 강의는 jpa2가 아닌 spring data jpa를 수강할 예정이다!

profile
Slow and Steady

0개의 댓글