@XtoOne
관계는 모두 기본이 즉시 로딩으로 설정되어 있는데 이것은 매우 위험하다.
따라서 지연로딩으로 설정해줘야 한다!
@ManyToOne
@OneToOne
➡️ @XToOne(fetch = FetchType.LAZY)
와 같이 추가해주자!
Order
// ====양방향 연관관계 편의 메서드====
// 양방향이더라도 위치는 컨트롤 하는 쪽에서 작성하는 것이 좋음
public void setMember(Member member) {
this.member = member;
member.getOrders().add(this);
}
public void addOrderItem(OrderItem orderItem) {
orderItems.add(orderItem);
orderItem.setOrder(this);
}
public void setDelivery(Delivery delivery) {
this.delivery = delivery;
delivery.setOrder(this);
}
// ====양방향 연관관계 편의 메서드====
// 양방향이더라도 위치는 컨트롤 하는 쪽에서 작성하는 것이 좋음
public void addChildCategory(Category child) {
this.child.add(child);
child.setParent(this);
}
양방향인 경우 어느 곳이든 메서드를 생성해도 되지만,
제어권을 가지고 있는 쪽에서 생성하면 좋다!
MemberRepository.java
package sorzzzzy.dearmydog.repository;
import org.springframework.stereotype.Repository;
import sorzzzzy.dearmydog.domain.Member;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
@Repository
public class MemberRepository {
// JPA 가 제공하는 표준 어노테이션
// 스프링이 엔티티 매니저를 만들어서 자동으로 주입해줌
@PersistenceContext
private EntityManager em;
public void save(Member member) {
em.persist(member);
}
// 단건 조회
public Member findOne(Long id) {
return em.find(Member.class, id);
}
// 리스트 조회
public List<Member> findAll() {
// 첫번째 인자 : JPQL, 두번째 인자 : 반환타입
return em.createQuery("select m from Member m", Member.class)
.getResultList();
}
// 이름으로 조회
public List<Member> findByName(String name) {
// 첫번째 인자 : JPQL, 두번째 인자 : 반환타입
return em.createQuery("select m from Member m where m.name = :name", Member.class)
.setParameter("name", name)
.getResultList();
}
}
MemberService.java
package sorzzzzy.dearmydog.service;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sorzzzzy.dearmydog.domain.Member;
import sorzzzzy.dearmydog.repository.MemberRepository;
import java.util.List;
@Service
// 'readOnly = true' 옵션은 읽기 전용 트랜잭션에서 성능을 최적화 시켜줌
@Transactional(readOnly = true)
// final이 있는 필드의 생성자 자동 생성
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
// 회원 가입
@Transactional // 데이터가 변경되어야 하는 부분에는 따로 어노테이션을 붙임
public Long join(Member member) {
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
// 중복 회원 검증
private void validateDuplicateMember(Member member) {
// 문제가 생기면 예외 발생
List<Member> findMembers = memberRepository.findByName(member.getName());
if (!findMembers.isEmpty()) {
throw new IllegalStateException("이미 존재하는 회원입니다.");
}
}
// 회원 전체 조회
public List<Member> findMembers() {
return memberRepository.findAll();
}
// 회원 단건 조회
public Member findOne(Long memberId) {
return memberRepository.findOne(memberId);
}
}
@Transactional(readOnly = true)
옵션은 읽기 전용 트랜잭션에서성능을 최적화 시켜준다.readOnly = true
옵션을 지정해주고, 데이터가 변경되어야 하는 부분에는 따로 @Transactional
를 붙여준다.@RequiredArgsConstructor
는 final
이 있는 필드의 생성자를 자동으로 만들어준다.📌
MemberRepository
도 수정@Repository @RequiredArgsConstructor public class MemberRepository { private final EntityManager em;