본문 바로가기

코딩/Java, SpringBoot

(25)
JPA 책 603p 603p의 내용 "스프링 OSIV"는 "기존의 OSIV"를 수정했다. 컨트롤러에서는 엔티티를 변경해도 변경감지가 동작하지 않음. 하지만 예외가 있다. 컨트롤러에서 엔티티의 set함수를 호출한 뒤에 트랜잭션을 시작하면 DB의 내용이 변경된다. 위의 내용이 잘 이해되지 않았다. 알아보자.! 먼저 영속성 컨텍스트와 트랜잭션에 대해 알고 있어야 한다. 영속성 컨텍스트 : SQL지연쓰기, snapshot, 엔티티 1차 캐시를 가지고 있다. JPA의 대부분의 기능은 영속성컨텍스트 때문에 가능한 것이다. 트랜잭션은 거들 뿐임. 트랜잭션 : 트랜잭션이 있어야 데이터 쓰기(변경포함)할 수 있다. 트랜잭션 없이 데이터 변경, 쓰기는 불가능하다. 예외발생함. 알아야할 것이 스프링 기본전략은 트랜잭션과 영속성 컨텍스트의 생명..
OSIV는 언제 사용할까? 김영한님의 JPA책 595p를 읽다가 생각을 정리한 글. 전통적 OSIV에서는 컨트롤러에서도 변경감지 기능이 동작해서 별로라고 한다. 책에서는 OSIV(요청당 트랜잭션)를 활성화 시켜 엔티티가 컨트롤러까지 존재하고 컨트롤러에서도 트랜잭션, 영속성 컨텍스트가 살아있는 상황을 얘기하고 있다. 여기서 엔티티인 고객 이름을 단순히 뷰에 노출할 때만 다른 이름으로변경하고 싶은 상황을 설명하고 있음. 이때 set()을 호출하면 변경감지가 동작해서 뷰에서 보여줄 때만 다른 이름으로 변경하고 싶은 것인데 DB까지 바뀌니까 좋지 않다고 한다. 내 생각. 처음에는 그냥 OSIV를 키고 이름을 상황에 따라 다르게 보여줘야하면 다른 객체 만들어서 매핑, 이름 바꾸고 그걸 반환하면 되잖아… 라고 생각했다. 근데 그러면 굳이 O..
presentation layer, service layer 명확히 구분 짓는 코드 JPA김영한님의 책을 읽고 있다. 13장에서 프리젠테이션, 서비스, 레포지토리 레이어의 분리와 역할침범에 대해서 많이 나온다. 고민하다가 내가 쓴 코드가 꽤나 문제를 해결해주는 것 같아서 블로그로 남기고자 한다. 먼저 레이어간 침범이 일어나는 경우가 뭔지 알아보자(JPA 책 584p에 잘 설명되어 있다.) 뷰에서 필요한 정보에 따라 다른 서비스 레이어 메소드가 필요한 경우. 뷰까지는 영속성 컨텍스트와 트랜잭션이 살아있지 않기 때문에 지연로딩이 불가능하다. 지연로딩이 불가능하기 때문에 프록시 객체를 강제 초기화 하는 방법을 사용하면 뷰마다 어떤 정보가 필요한지 알고 메소드마다 같은 기능을 하더라도 어떤 메소드는 프록시 객체를 강제 초기화. 어떤 메소드는 초기화 하지 않고 반환하게 된다. 최적화를 위해서라면..
이건 해결해야겠다. save() 2번 호출했을 때 왜 연관된 엔티티가 영속상태가 아닌데도 save()에서 예외가 발생하지 않는가? 아래의 코드에서 예외가 발생해야 한다는게 내 생각이다. 1. 엔티티를 저장할 때 연관된 엔티티는 영속상태이어야 한다. 2. 영속성 컨텍스트는 트랜잭션이 begin할 때 생성되고 commit할 때 닫힌다. 위의 2개의 사실을 종합해봤을 때 아래 코드에서 예외가 발생해야한다. 그렇지만 예외가 발생하지 않는다. @SpringBootTest //@Transactional //트랜잭션을 지웠다. class CakeRepositroyTest { @Autowired CakeRepositroy cakeRepositroy; @Autowired StoreRepository storeRepository; @Test public void saveTest() { Store s = Store.builder() .name("스토어..
[Jackson] java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class X / Map<-> Object : convertValue() / jackson always needs Getter!! 공모전 준비중인 MyOrder가 거의 개발을 끝냈다. 시연동영상을 제출해야하기 때문에 시연 동영상 시나리오를 짜고 마감전에 미리 시나리오 테스트를 진행해보려 한다. 근데 제목과 같이 자꾸 예외가 발생했다. 원인을 글 맨 밑의 링크에서 쉽게 찾을 수 있었다. 이 내용을 짧게 정리하고자 한다. @Test public void scenarioTest() throws Exception { List demands = testRepository.insertAll(); //사용자 가져오기 MvcResult mvcResult = mvc.perform(get("/get-test-customer")) .andExpect(status().isOk()) .andExpect(jsonPath("$.jwt").exists()) ...
형식을 알지 못하는 JSON을 클래스로 만들 수 있을까? 먼저 도대체 형식을 알지 못하는 JSON을 파싱해야하는 경우가 어떤 경우인지 알아보자. 여러 가지를 정할 수 있는 음식주문 서비스를 생각해보자. 가게마다 가능한 옵션이 다를 것이다. 중국집에는 짜장면 : [오이x, 양파x, 파x, 고기x]. 분식집에서는 라면 : [계란o, 파o, 양파o, 고기o] 와 같은 옵션이 가능할 것이다. 이것을 DB에 어떻게 저장할 수 있을까? 컬럼에는 저장이 불가능하다고 판단했고..무한 컬럼을 사용할 수는 없으니까...DB에 JSON 형식을 사용해서 저장하기로 했다. 그리고 클라이언트가 json을 알아서 파싱해서 사용하기로 했다. json object 변환에 대해서는 여러 라이브러리가 있고 자료도 많다. 하지만 이 상황은 전부 JSON응답 형식을 알고 있을 때 변환하는 상황이다..
[SpringBoot] 엔티티에는 setter를 두지 않는다. 확장성 있는 함수구성 왜 엔티티에 setter를 두지 않는지 몇개의 블로그를 읽고 정리했다. https://velog.io/@aidenshin/%EB%82%B4%EA%B0%80-%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94-JPA-%EC%97%94%ED%8B%B0%ED%8B%B0-%EC%9E%91%EC%84%B1-%EC%9B%90%EC%B9%99 JPA 엔티티 작성 - Setter 금지 엔티티를 작성함에 제가 생각하는 몇가지 원칙(?)이 있습니다.그중 엔티티(객체)의 Setter 사용 금지 원칙(?) 에 대해 알아보겠습니다.엔티티를 작성할 때 습관적으로 모든 필드에 Setter를 생성하는 velog.io setter는 메서드의 의도를 알기 힘들다. setter가 아닌 상황에 맞는 메서드를 만들어서(사실 기..
SpringBoot static final에 DI하기? 아래는 Test클래스의다. 보통 Autowired를 사용할 때는 final 을 사용했다. final을 사용하면 빨간줄 뜬다. static을 빼고 final만 사용하면 빨간줄 안뜬다. -> 객체의 생성시점이 달라서 그렇다. static은 스프링 빈이 로딩되기 전에 초기화 된다. static final은 static변수가 생성되면서 바로 초기화되어야 하는데 이 시점에는 아직 빈이 없기 때문에 값을 넣을 수가 없는 것. static final에 빈을 넣을 수는 없다. (final은 생성과 동시에 초기화 해야함.) static이 있으면 static을 담고 있는 객체가 생성되기 전에 바로 객체가 생성되기 때문에 final을 붙이면 에러뜨는 것.(context가 로드되지 않은 시점에서 초기화 되기 때문에 null인..