참고 : 인프런 < 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 김영한 >
강의에서는 예제를 보이기 위해 Setter을 사용하였지만,
실무에서는 추후 유지보수가 어렵기 때문에 가급적 사용하지 않는다.
즉시로딩( EAGER ) : 엔티티를 조회할 때 연관된 엔티티도 함께 조회
지연로딩( LAZY ) : 엔티티를 조회할 때 연관된 엔티티를 즉시 로드하지 않고, 해당 엔티티가 실제로 접근될 때까지 로딩을 지연
연관된 엔티티를 함께 DB에서 조회해야 하면, fetch join 또는 엔티티 그래프 기능을 사용
@XToOne(OneToOne, ManyToOne) 관계는 기본이 즉시로딩이므로 직접 지연로딩으로 설정
설정 방법
연관된 엔티티의 필드에 @OneToMany, @ManyToOne, @OneToOne, @ManyToMany 어노테이션을 사용하면서 fetch 속성을 FetchType.XXX 설정@OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "address_id") private Address address;
컬렉션을 초기화하는 방법은 2가지 이다.
private List<Order> orders = new ArrayList<>();
public Member(){
orders=new ArrayList<>();
}
컬렉션은 필드에서 바로 초기화 하는 것이 안전하다.
getOrders() 처럼 임의의 메서드에서 컬력션을 잘못 생성하면 하이버네이트 내부 메커니즘에 문제가 발생 할 수 있다. 따라서 필드레벨에서 생성하는 것이 가장 안전하고, 코드도 간결하다.Member member = new Member();
System.out.println(member.getOrders().getClass());
em.persist(member);
System.out.println(member.getOrders().getClass());
//출력 결과
class java.util.ArrayList
class org.hibernate.collection.internal.PersistentBag
스프링 부트에서 하이버네이트 기본 매핑 전략을 변경해서 실제 테이블 필드명은 다르다.
스프링 부트 신규 설정 (엔티티(필드) 테이블(컬럼))
1. 카멜 케이스 언더스코어(memberPoint memberpoint)
2. .(점) (언더스코어)
3. 대문자 소문자
적용 2 단계
1. 논리명 생성: 명시적으로 컬럼, 테이블명을 직접 적지 않으면 ImplicitNamingStrategy 사용
spring.jpa.hibernate.naming.implicit-strategy : 테이블이나, 컬럼명을 명시하지 않을 때 논리명 적 용,
2. 물리명 적용:
spring.jpa.hibernate.naming.physical-strategy : 모든 논리명에 적용됨, 실제 테이블에 적용 (username usernm 등으로 회사 룰로 바꿀 수 있음)
스프링 부트 기본 설정
spring.jpa.hibernate.naming.implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy spring.jpa.hibernate.naming.physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
cascade = CascadeType.ALL
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id")
private Address address;
// Getters and Setters
}
@Entity
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String street;
private String city;
private String state;
// Getters and Setters
}
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class Main {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("example-unit");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// Address 생성
Address address = new Address();
address.setStreet("123 Main St");
address.setCity("Anytown");
address.setState("Anystate");
// Student 생성
Student student = new Student();
student.setName("John Doe");
student.setAddress(address);
// Student 저장 (Address도 함께 저장됨)
em.persist(student);
em.getTransaction().commit();
em.getTransaction().begin();
// Student 조회
Student foundStudent = em.find(Student.class, student.getId());
System.out.println("Student Name: " + foundStudent.getName());
System.out.println("Student Address: " + foundStudent.getAddress().getStreet());
// Student 삭제 (Address도 함께 삭제됨)
em.remove(foundStudent);
em.getTransaction().commit();
em.close();
emf.close();
}
}
@Entity
@Table(name="orders")
public class Order {
@Id @GeneratedValue
@Column(name="order_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="member_id")
private Member member;
@OneToMany(mappedBy = "order",cascade = CascadeType.ALL)
private List<OrderItem> orderItems;
@OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
@JoinColumn(name = "delivery_id")
private Delivery delivery;
private LocalDateTime orderDate;
@Enumerated(EnumType.STRING)
private OrderStatus status;
//==연관관계 메서드==//
// 회원 정보 설정 및 양방향 관계 설정
public void setMember(Member member){
this.member=member;
member.getOrders().add(this); // 회원 엔티티의 orders에 현재 주문을 추가
}
// 주문 상품 정보 추가 및 양방향 관계 설정
public void addOrderItem(OrderItem orderItem){
orderItems.add(orderItem); // 현재 주문에 주문 상품 추가
orderItem.setOrder(this); // 주문 상품 엔티티에 현재 주문 설정
}
// 배송 정보 설정 및 양방향 관계 설정
public void setDelivery(Delivery delivery){
this.delivery=delivery; // 현재 주문에 배송 정보 설정
delivery.setOrder(this); // 배송 정보 엔티티에 현재 주문 설정
}
}