![[JPA] 값 타입 공유문제](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYOGPJ%2Fbtst6jxHZeD%2F8P2q3kD8V7RCEunZ6jpR61%2Fimg.png)
임베디드 값타입을 공유하는 두 객체가 있다. 한 객체에서 임베디드 값타입을 수정하면 이를 공유하는 다른 객체의 임베디드 값타임도 수정된다. 이는 자바에서 참조값을 수정하면 이를 참조하는 모든 객체의 값이 바뀌는 것과 동일한 원리이다.
근데 막상 임베디드 타입을 수정하니 한 객체에서만 수정되는 상황이 발생했다. 분명 공부할 때는 이를 공유하는 모든 객체의 임베디드 타입이 수정된다고 배웠는데 왜 한 객체만 수정되는 걸까? 그 이유는 ORM을 잘못 이해하고 사용했기 때문이었다.
Member 엔티티
다른 필드들은 볼 필요없이 homeAddress 필드에만 집중하면 된다.
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
private int age;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city", column = @Column(name = "workCity")),
@AttributeOverride(name = "street", column = @Column(name = "workStreet")),
@AttributeOverride(name = "zipcode", column = @Column(name = "workZipcode"))
})
private Address workAddress;
@Embedded
private Address homeAddress;
@Embedded
private Period period;
@Embedded
private PhoneNumber phoneNumber;
// Getter, Setter, 생성자
}
처음에 아래와 같이 작성했다. member1과 member2은 동일한 HomeAddess(임베디드 타입)을 공유한다. 두 객체를 영속화시키고 flush를 통해 DB에 저장했다. 이후에 두 객체를 다시 꺼내어 member2의 HomeAddress를 수정했다. 내가 기대했던 것은 member1과 member2의 HomeAddress 둘 다 바뀌기를 기대했다. 그러나 member2의 HomeAddress만 수정됐다.
Address address = new Address("city", "street", "zipcode");
Member member1 = new Member("user1", 99, null, address,null, null);
em.persist(member1);
Member member2 = new Member("user1", 99, null, address,null, null);
em.persist(member2);
em.flush();
em.clear();
Member findMember1 = em.find(Member.class, member1.getId());
Member findMember2 = em.find(Member.class, member2.getId());
findMember2.getHomeAddress().setCity("newCity");
왜 이런 상황이 일어난 것일까? 그 이유는 DB에 저장된 객체의 HomeAddress를 수정했기 때문이다. DB에 저장되기 전에는 당연히 member1과 member2 둘 다 같은 HomeAddress를 공유한다. 이때 member2의 HomeAddress를 수정했다면 member1과 member2 둘 다 HomeAddress가 수정될 것이다. 객체와 테이블을 매핑하는 ORM을 잘못 이해하고 사용했기 때문에 이러한 상황이 발생한 것이다. DB에 저장된 객체는 HomeAddress가 공유된 임베디드 타입인지 아닌지 알 수가 없다.
아래와 같이 DB에 flush되기 전에 member2의 HomeAddress를 수정하면 member1과 member2의 HomeAddress가 둘 다 수정된다.
Address address = new Address("city", "street", "zipcode");
Member member1 = new Member("user1", 99, null, address,null, null);
em.persist(member1);
Member member2 = new Member("user1", 99, null, address,null, null);
em.persist(member2);
member2.getHomeAddress().setCity("newCity");
em.flush();
em.clear();
DB에 저장되기 전후의 주소값이 다름을 알 수 있다.
Address address = new Address("city", "street", "zipcode");
Member member1 = new Member("user1", 99, null, address,null, null);
em.persist(member1);
Member member2 = new Member("user1", 99, null, address,null, null);
em.persist(member2);
System.out.println("member1.getHomeAddress().getClass() = " + System.identityHashCode(member1.getHomeAddress()));
System.out.println("member2.getHomeAddress().getClass() = " + System.identityHashCode(member2.getHomeAddress()));
System.out.println("==============================================================");
em.flush();
em.clear();
Member findMember1 = em.find(Member.class, member1.getId());
Member findMember2 = em.find(Member.class, member2.getId());
System.out.println("findMember1.getHomeAddress().getClass() = " + System.identityHashCode(findMember1.getHomeAddress()));
System.out.println("findMember2.getHomeAddress().getClass() = " + System.identityHashCode(findMember2.getHomeAddress()));
tx.commit();
// 출력
member1.getHomeAddress().getClass() = 449954659
member2.getHomeAddress().getClass() = 449954659
==============================================================
findMember1.getHomeAddress().getClass() = 541713794
findMember2.getHomeAddress().getClass() = 1179314953
결론
ORM에 대해서 잘 이해하고 사용하자.