728x90
반응형
값 타입은 복잡한 객체 세상을 조금이라도 단순화하려고 만든 개념인데,
따라서 값 타입은 단순하고 안전하게 다룰 수 있어야 한다.
예를 들어, 한 주소 객체를 선언 했는데, 선언한 주소를 두 명의 멤버에 넣고, 주소를 변경시키는 경우,
두 명의 멤버의 주소가 모두 바뀌게 된다.
JpaMain.java
Address address = new Address("oldHome", "oldStreet", "zipcoode");
Member member1 = new Member();
member1.setUserName("member1");
member1.setHomeAddress(address);
em.persist(member1);
Member member2 = new Member();
member2.setUserName("member2");
member2.setHomeAddress(address);
em.persist(member2);
member1.getHomeAddress().setCity("newHome");
위 코드를 실행하면 member1, member2 모두 newHome으로 세팅되는 것을 확인할 수 있다.
Hibernate:
call next value for hibernate_sequence
Hibernate:
call next value for hibernate_sequence
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(INSERT_MEMBER, createdDate, UPDATE_MEMBER, lastModifiedDate, city, street, zipCode, TEAM_ID, USERNAME, WORK_CITY, WORK_STREET, WORK_ZIP_CODE, endDate, startDate, MEMBER_ID)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(INSERT_MEMBER, createdDate, UPDATE_MEMBER, lastModifiedDate, city, street, zipCode, TEAM_ID, USERNAME, WORK_CITY, WORK_STREET, WORK_ZIP_CODE, endDate, startDate, MEMBER_ID)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* update
hellojpa.Member */ update
Member
set
INSERT_MEMBER=?,
createdDate=?,
UPDATE_MEMBER=?,
lastModifiedDate=?,
city=?,
street=?,
zipCode=?,
TEAM_ID=?,
USERNAME=?,
WORK_CITY=?,
WORK_STREET=?,
WORK_ZIP_CODE=?,
endDate=?,
startDate=?
where
MEMBER_ID=?
Hibernate:
/* update
hellojpa.Member */ update
Member
set
INSERT_MEMBER=?,
createdDate=?,
UPDATE_MEMBER=?,
lastModifiedDate=?,
city=?,
street=?,
zipCode=?,
TEAM_ID=?,
USERNAME=?,
WORK_CITY=?,
WORK_STREET=?,
WORK_ZIP_CODE=?,
endDate=?,
startDate=?
where
MEMBER_ID=?
3월 08, 2023 9:51:56 오전 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:h2:tcp://localhost/~/jpaStudy2]
Process finished with exit code 0
Member1, Member2 가 있으니
insert 문이 2번 나가는게 맞는데, update문도 2번 나가게 되었다.
이렇게 두 객체가 하나의 값을 같이 참조해버리니까 하나를 바꿀 때, 두 객체의 값이 모두 변하게 되는 현상이 발생한다.
이처럼 값 타입이 공유될 때, 값의 주소를 참조하게 되므로 값 변경 시 부작용이 발생한다.
하지만 값 타입을 복사한다면 안전하게 사용이 가능하다.
JpaMain.java
Address address = new Address("city", "street", "10000");
Member member = new Member();
member.setUserName("member1");
member.setHomeAddress(address);
em.persist(member);
// address를 새로 인스턴스를 만들지 않으면 아래 newCity를 넣을 때 두번의 update 쿼리가 나간다.
Address copyAddress = new Address(address.getCity(), address.getStreet(), address.getZipCode());
Member member2 = new Member();
member2.setUserName("member2");
member2.setHomeAddress(copyAddress);
em.persist(member2);
member.getHomeAddress().setCity("newCity");
아래는 실행 결과다.
Hibernate:
call next value for hibernate_sequence
Hibernate:
call next value for hibernate_sequence
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(INSERT_MEMBER, createdDate, UPDATE_MEMBER, lastModifiedDate, city, street, zipCode, TEAM_ID, USERNAME, WORK_CITY, WORK_STREET, WORK_ZIP_CODE, endDate, startDate, MEMBER_ID)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(INSERT_MEMBER, createdDate, UPDATE_MEMBER, lastModifiedDate, city, street, zipCode, TEAM_ID, USERNAME, WORK_CITY, WORK_STREET, WORK_ZIP_CODE, endDate, startDate, MEMBER_ID)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
/* update
hellojpa.Member */ update
Member
set
INSERT_MEMBER=?,
createdDate=?,
UPDATE_MEMBER=?,
lastModifiedDate=?,
city=?,
street=?,
zipCode=?,
TEAM_ID=?,
USERNAME=?,
WORK_CITY=?,
WORK_STREET=?,
WORK_ZIP_CODE=?,
endDate=?,
startDate=?
where
MEMBER_ID=?
insert는 2번, update는 1번 실행됐다.
이렇듯 값을 복사하여 사용한다면 두 가지 값이 모두 변하지 않는 모습을 확인할 수 있다.
이렇게 항상 값을 복사해서 사용하면 공유 참조로 인해 발생하는 부작용을 피할 수 있다.
임베디드 타입은 직접 정의한 값 타입이라 자바의 기본 타입이 아니라 객체 타입인데,
이런 객체 타입은 참조 값을 직접 대입하는 것을 막을 방법이 없다.
객체의 공유 참조는 피할 수 없다.
객체 타입을 불변 객체로 만들면 참조를 전달하는 것을 막을 수 있다.
- 객체 타입을 수정할 수 없게 만들면 부작용을 원천 차단할 수 있다.
- 값 타입은 불변 객체(immutable object)로 설계해야 한다.
- 불변 객체 : 생성 시점 이후 절대 값을 변경할 수 없는 객체이다.
- 생성자로만 값을 설정하고 수정자(Setter)를 만들지 않으면 된다,
- 참고 : Integer, String은 자바가 제공하는 대표적인 불변 객체이다.
728x90
반응형
'자바 > JPA' 카테고리의 다른 글
[JPA/Java] For property-based access both setter and getter should be present 문제 해결 @Access or @Column (0) | 2023.03.13 |
---|---|
[JPA/Java] 값 타입 3 (값 타입 컬렉션) (0) | 2023.03.13 |
[JPA/Java] 값 타입 1 (기본 값, 임베디드(복합 값) 타입) (0) | 2023.03.06 |
[JPA/Java] 영속성 전이 : Cascade, 고아 객체 (0) | 2023.03.03 |
[JPA/Java] 즉시 로딩과 지연 로딩 (2) | 2023.03.02 |
댓글