[JPA] 값 타입

보람·2023년 5월 4일
0

Spring

목록 보기
15/18

💱 값 타입

(1) 엔티티 타입 vs 값 타입

◾ 엔티티 타입

  • @Entity를 붙여서 관리하던 클래스들
  • PK값으로 관리가 되기때문에 데이터가 변해도 쉽게 추적이 가능하고 관리도 편리

👀 PK값

  • "Primary Key(기본 키)"
  • 각 레코드를 고유하게 식별하는 데 사용되는 필드(열) ex. 사용자 고유의 ID

◾ 값 타입

  • int, String과 같은 단순히 값으로 사용하는 자바 기본타입이나 객체
  • 추적하기가 어려움

(2) 값 타입

1) 기본값 타입

  • 자바 기본타입(int, double..), 래퍼클래스(Integer, Long..), String
  • 생명주기를 엔티티한테 의존
  • 예를 들어, Order 엔티티를 생성할 때 함께 OrderDate 객체생성되며, Order 엔티티가 삭제될 때 OrderDate 객체도 함께 삭제

2) 임베디드 타입

  • 복합 값타입으로 새로운 값 타입을 직접 정의할 수 있다.
  • 예를 들어 회원 정보에서 비슷한 정보끼리 묶어 관리하고 싶다면 그런 묶음을 임베디드 타입으로 만들어 주고 사용

(3) 임베디드 타입(EMBEDDED TYPE)

  • Period : 회원 정보 중 startDate, endDate를 묶은 것
  • Address : 회원 정보 중 city, street, zipcode를 묶은 것
  • 이런 묶음을 임베디드 타입이라고 함

1) JPA에서 임베디드 타입 사용법

  • @Embeddable
    • 값 타입을 정의하는 곳에 표시
  • @Embedded
    • 값 타입을 사용하는 곳에 표시
  • 기본 생성자 필수
  • @Embeddable@Embedded 둘 중에 하나만 넣어도 되지만 둘 다 넣는 것을 권장

💡 예시

  • @Embeddable
@Embeddable
@Getter @Setter
public class Address {

	private String city;
	private String street;
	private String zipcode;
	
	public Address(String city, String street, String zipcode) {
		super();
		this.city = city;
		this.street = street;
		this.zipcode = zipcode;
	}	
	// 기본생성자는 반드시 있어야 한다.
	public Address() { }
}
  • @Embedded
@Entity
@Getter @Setter
public class Member {

	@Id @GeneratedValue
	private Long id;
	
	@Column(name = "name", nullable = false)
	private String username;

	@Embedded
	private Address address;
		
}
  • 실행파일에서 사용하기
try {
	 Member member = new Member();
     member.setUsername("user");
	 member.setAddress(new Address("서울", "역삼", "123"));
 }    

2) 임베디드 타입의 장점

  • 재사용성
  • 높은 응집도
  • 임베디드 타입에 사용할 특정 메서드를 따로 관리가능
  • 임베디드 타입을 포함한 모든 값 타입은 값 타입을 소유한 엔티티 생명주기를 의존

3) 임베디드 타입과 테이블 매핑

  • 임베디드 타입은 엔티티의 값
  • 임베디드 타입을 사용하기 전과 후에 매핑하는 테이블은 같음
  • 객체와 테이블은 아주 세밀하게 매핑하는 것이 가능
  • 잘 설계한 ORM 애플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많음

4) @AttributeOverride : 속성 재정의

  • 같은 임베디드 타입을 여러 개 쓰고 싶은 경우 @AttributeOverrides, @AttributeOverride어노테이션 사용

💡 예시

	// 집주소
	@Embedded
	private Address address;
    
    // 회사 주소
	@Embedded
	@AttributeOverrides({
		@AttributeOverride(name = "city", column = @Column(name = "WORK_CITY")),
		@AttributeOverride(name = "street", column = @Column(name = "WORK_STREET")),
		@AttributeOverride(name = "zipcode", column = @Column(name = "WORK_ZIPCODE"))
	})
	private Address workAddress;
	

5) 객체 타입의 한계

💡 하나의 객체 타입 값을 2객체에 할당

	Address addr = new Address("서울", "역삼", "123");
	
	Member member = new Member();
	member.setUsername("user1");
	member.setAddress(addr);
	em.persist(member);
			
	Member member2 = new Member();
	member2.setUsername("user2");
	member2.setAddress(addr);
	em.persist(member2);
			
	tx.commit();

💡 그 중 한 객체의 값 변경

	member.getAddress().setCity("newCity");

👍 결과 🚫 오류 user1, user2의 city값이 다 바뀜 🚫

  • 이유

    • 기본데이터 타입 변수일 때 -> 재할당 가능
      • a라는 공간에 10 대입
      • b라는 공간에 a값 복붙
    		int a = 10; 
    		int b = a
    • 객체 공유 : 클래스 공유

      • 공간 없음
      • 각각의 클래는 주소값을 가지고 있는 new Member() 객체를 가리키기만 하고 있음
      • 그러므로 member1 클래스에서 city값을 바꾸면 new Member() 객체 주소의 city 변경
      • member2 클래스는 바뀐 new Member()객체를 그대로 가리키고 있음
      • 밖에서 볼 때는 a, b클래스 city값 전체 수정
  • 임베디드 타입처럼 직접 정의한 값 타입은 자바의 기본타입이 아니라 객체 타입
    • 자바 기본 타입에 값을 대입하면 값을 복사한다.
    • 객체 타입은 참조 값을 직접 대입하는 것을 막을 방법이 없음
  • 항상 값을 복사해서 사용하면 공유 참조로 인해 발생하는 부작용을 피할 수 있음
  • 해결법
    • 새로운 객체를 무조건 만들어서 할당
    • setter를 없앤다

💡 기본값타입들을 복사해서 넘겨주는 방식

	Address addr = new Address("서울", "역삼", "123");
    // 새로운 객체 생성
	Address copyAddr = new Address(addr.getCity(), addr.getStreet(), addr.getZipcode());
			
	Member member = new Member();
	member.setUsername("user1");
	member.setAddress(addr);
	em.persist(member);
		
	Member member2 = new Member();
	member2.setUsername("user2");
    // 새로운 객체 할당
	member2.setAddress(copyAddr);
	em.persist(member2);
			
	// 1번째 member 주소만 바꾸고 싶어
	member.getAddress().setCity("newCity");
			
	tx.commit();
profile
안녕하세요, 한보람입니다.

0개의 댓글