아래의 코드에서 예외가 발생해야 한다는게 내 생각이다.
1. 엔티티를 저장할 때 연관된 엔티티는 영속상태이어야 한다.
2. 영속성 컨텍스트는 트랜잭션이 begin할 때 생성되고 commit할 때 닫힌다.
위의 2개의 사실을 종합해봤을 때 아래 코드에서 예외가 발생해야한다. 그렇지만 예외가 발생하지 않는다.
@SpringBootTest
//@Transactional //트랜잭션을 지웠다.
class CakeRepositroyTest {
@Autowired
CakeRepositroy cakeRepositroy;
@Autowired
StoreRepository storeRepository;
@Test
public void saveTest() {
Store s = Store.builder()
.name("스토어")
.build();
storeRepository.save(s); //영속성 컨텍스트가 생겼다가 없어짐.
s.setFcmToken("1");//여기서 set해도 영속상태가 아니라서 update 문이 사용되지 않는다.
//확실히 영속성 컨텍스트가 닫힌걸 확인할 수 있음.
Cake c = Cake.builder()
.name("케이크")
.store(s)
.build();
cakeRepositroy.save(c);//영속성 컨텍스트가 새로 생기고 저장할 텐데 s는 영속상태가 아니다.
//연관된 엔티티가 영속상태가 아닌데 어떻게 저장 가능한가?
}
//실행결과
Hibernate:
insert
into
store
(created, modified, birth_year, close_time, description, email, fcm_token, file_path, gender, impossible_date, latitude, location, longitude, name, open_time, owner_phone_num, sns_identify_key, sns_type, store_phone_num, uuid)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2022-08-13 00:51:24.278 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [TIMESTAMP] - [2022-08-13T00:51:24.225721700]
2022-08-13 00:51:24.279 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [TIMESTAMP] - [2022-08-13T00:51:24.225721700]
2022-08-13 00:51:24.280 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [INTEGER] - [0]
2022-08-13 00:51:24.280 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [TIME] - [null]
2022-08-13 00:51:24.281 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [5] as [VARCHAR] - [null]
2022-08-13 00:51:24.281 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [6] as [VARCHAR] - [null]
2022-08-13 00:51:24.281 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [7] as [VARCHAR] - [null]
2022-08-13 00:51:24.281 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [8] as [VARCHAR] - [null]
2022-08-13 00:51:24.281 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [9] as [VARCHAR] - [null]
2022-08-13 00:51:24.281 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [10] as [VARCHAR] - [null]
2022-08-13 00:51:24.282 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [11] as [DOUBLE] - [0.0]
2022-08-13 00:51:24.283 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [12] as [VARCHAR] - [null]
2022-08-13 00:51:24.283 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [13] as [DOUBLE] - [0.0]
2022-08-13 00:51:24.283 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [14] as [VARCHAR] - [스토어]
2022-08-13 00:51:24.283 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [15] as [TIME] - [null]
2022-08-13 00:51:24.283 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [16] as [VARCHAR] - [null]
2022-08-13 00:51:24.283 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [17] as [VARCHAR] - [null]
2022-08-13 00:51:24.283 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [18] as [VARCHAR] - [null]
2022-08-13 00:51:24.283 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [19] as [VARCHAR] - [null]
2022-08-13 00:51:24.284 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [20] as [BINARY] - [72cd15f7-48aa-4a15-a401-840fb19a8794]
Hibernate:
insert
into
cake
(description, file_path, min_price, name, option, store_uuid, uuid)
values
(?, ?, ?, ?, ?, ?, ?)
2022-08-13 00:51:51.775 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [null]
2022-08-13 00:51:51.776 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [null]
2022-08-13 00:51:51.776 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [INTEGER] - [0]
2022-08-13 00:51:51.777 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [VARCHAR] - [케이크]
2022-08-13 00:51:51.777 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [5] as [VARCHAR] - [null]
2022-08-13 00:51:51.778 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [6] as [BINARY] - [72cd15f7-48aa-4a15-a401-840fb19a8794]
2022-08-13 00:51:51.778 TRACE 22520 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [7] as [BINARY] - [9853f92b-00d9-4bd7-a9df-b285913ab47d]
Disconnected from the target VM, address: '127.0.0.1:64494', transport: 'socket'
2022-08-13 00:52:08.392 INFO 22520 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2022-08-13 00:52:08.394 INFO 22520 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2022-08-13 00:52:08.398 INFO 22520 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
Process finished with exit code 0
아니면 cakeRepository.save()를 호출할때 s는 PK가 있으니까 persist()가 아니라 merge를 호출하는 것인가?
JPA책 563p를 보면 save는 pk가 있으면 merge, 없으면 save를 호출한다고 한다. s는 pk가 있으니까 merge를 사용. merge는 1차캐시에서 찾고 없으면 DB까지 뒤진다. 하지만 store를 찾는 select문은 호출되지 않았다...ㅇㄴ뭐야...이래서 기술은 정확하게 알고 사용해야한다...
아래와 같이 실행해보았다.
@Test
public void saveTest() {
Store s = Store.builder()
.name("스토어")
.build();
storeRepository.save(s);
UUID uuid = s.getUuid();
s.setFcmToken("1");//영속상태 아님. 변경감지 동작안함.
Store store = Store.builder()//uuid만 받아서 새로운 store객체를 만들었다. name은 사라지고 description에 "테스트"값이 들어가는지 테스트해보자.
.uuid(uuid)
.description("테스트")
.build();
Cake c = Cake.builder()
.name("케이크")
.store(store)
.build();
cakeRepositroy.save(c);
}
결론적으로 store.description에는 "테스트"가 들어가지 않았다. 아래에서 볼 수 있듯이 name은 "스토어"로 그대로 였다.
결론 : ORM책 174p에서 연관관계 엔티티는 모두 영속상태여야 한다고 했는데 영속상태가 아니라 DB에 있기만 하면 되는 것 같다(PK-FK관계에서 당연한 제약사항임. 이것만 신경쓰면 되는 듯.!).. DB에서 join으로 검사해보았을 때 연관관계는 잘 설정되었다. 다만 store의 uuid값만 읽고 나머지는 다 버렸음을 알 수 있다.(description컬럼을 업데이트 하지 않았으니까.)
'코딩 > Java, SpringBoot' 카테고리의 다른 글
OSIV는 언제 사용할까? (0) | 2022.08.13 |
---|---|
presentation layer, service layer 명확히 구분 짓는 코드 (0) | 2022.08.13 |
[Jackson] java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class X / Map<-> Object : convertValue() / jackson always needs Getter!! (0) | 2022.08.05 |
형식을 알지 못하는 JSON을 클래스로 만들 수 있을까? (0) | 2022.08.05 |
[SpringBoot] 엔티티에는 setter를 두지 않는다. 확장성 있는 함수구성 (0) | 2022.08.05 |