인프런 커뮤니티 질문&답변

lwisekiml님의 프로필 이미지

작성한 질문수

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

OSIV와 성능 최적화

open-in-view값 true/false

작성

·

93

0

 

@Controller
@RequiredArgsConstructor
@RequestMapping("/board")
public class BoardController {
 @PostMapping("/update")
    public String update(@ModelAttribute BoardDTO boardDTO, Model model) {
        BoardDTO board = boardService.update(boardDTO);
        model.addAttribute("board", board);
        return "detail";
    }
}

 

@Service
@RequiredArgsConstructor
public class BoardService {

    private final BoardRepository boardRepository;

    public BoardDTO findById(Long id) {
        System.out.println("findById : "+ em.getDelegate());
		// 이 아래 코드에서 질문 있습니다.
        Optional<BoardEntity> optionalBoardEntity = boardRepository.findById(id);
        if (optionalBoardEntity.isPresent()) {
            BoardEntity boardEntity = optionalBoardEntity.get();
            return BoardDTO.toBoardDTO(boardEntity);
        } else {
            return null;
        }
    }

    public BoardDTO update(BoardDTO boardDTO) {
        System.out.println("update : "+ em.getDelegate());
        BoardEntity boardEntity = BoardEntity.toUpdateEntity(boardDTO);
        boardRepository.save(boardEntity);
        return findById(boardDTO.getId());
    }
}

 

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Getter
public class BaseEntity {
    @CreationTimestamp
    @Column(updatable = false)
    private LocalDateTime createdTime;

    @UpdateTimestamp
    @Column(insertable = false)
    private LocalDateTime updatedTime;
}

 

@Entity
@Getter @Setter
@Table(name = "board_table")
public class BoardEntity extends BaseEntity {
    @Id GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String boardWriter;
    private String boardPass;
    private String boardTitle;
    private String boardContents;
    private int boardHits;
	
	public static BoardEntity toUpdateEntity(BoardDTO boardDTO) {
        BoardEntity boardEntity = new BoardEntity();
        boardEntity.setId(boardDTO.getId());
        boardEntity.setBoardWriter(boardDTO.getBoardWriter());
        boardEntity.setBoardPass(boardDTO.getBoardPass());
        boardEntity.setBoardTitle(boardDTO.getBoardTitle());
        boardEntity.setBoardContents(boardDTO.getBoardContents());
        boardEntity.setBoardHits(boardDTO.getBoardHits());
        return boardEntity;
    }
}

 

위에 코드 상황에서 open-in-view를 true로 하면 optionalBoardEntity에 createdTime 값이 null입니다.

 

제 생각으로는 open-in-view가 true 이므로 update()에서 (createdTime 값이 없는) boardEntity가 영속성 컨텍스트 1차 캐시에 존재하고, findById()에서 boardRepository.findById(id) 값을 호출하지만 1차캐시에 있는 값을 줘서 최종적으로 boardEntity값에는 createdTime값이 없는 것으로 이해했습니다.

 

그런데 왜 open-in-view값을 false로 하면 boardEntity에 createdTime 값이 있는지 모르겠습니다.

 

open-in-view가 true 이건 false 이건 영속성 컨텍스트 생존 범위에 Service는 포함되니 createdTime 값이 둘 다 없어야 되는것이 아닌지 궁금합니다.

답변 1

0

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. lwisekiml님

도움을 드리고 싶지만 질문 내용만으로는 답변을 드리기 어렵습니다.

실제 동작하는 전체 프로젝트를 ZIP파일로 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.

구글 드라이브 업로드 방법은 다음을 참고해주세요.

https://bit.ly/3fX6ygx

 

주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요

 

추가로 다음 내용도 코멘트 부탁드립니다.

1. 문제 영역을 실행할 수 있는 방법

2. 문제가 어떻게 나타나는지에 대한 상세한 설명 (오류 화면, 오류 로그 포함)

 

링크: 공식 서포터즈

링크: 자주하는 질문

감사합니다.

lwisekiml님의 프로필 이미지
lwisekiml
질문자

https://drive.google.com/file/d/1H0CJLp_dNX_jlm00iipeNtgYYwGwgeSF/view?usp=drive_link

 

실행 방법과 순서는 첨부파일에 추가하였습니다.^^

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. lwisekiml님

우선 osiv 설정과 무관하게 항상 트랜잭션 안에서 엔티티를 조회하고 변경하는 방법을 고민하셔야 합니다.

서비스에서 업데이트 메서드를 다음과 같이 트랜잭션 안에서 엔티티를 조회하고, 변경 감지를 통해 변경한다면 원하는 결과를 확인하실 수 있을거에요.

    @Transactional
    public BoardDTO update(BoardDTO boardDTO) {
        System.out.println("update : "+ em.getDelegate());
        BoardEntity boardEntity = boardRepository.findById(boardDTO.getId()).get();
        boardEntity.setBoardWriter(boardDTO.getBoardWriter());
        boardEntity.setBoardTitle(boardDTO.getBoardTitle());
        boardEntity.setBoardContents(boardDTO.getBoardContents());
        return findById(boardDTO.getId());
    }

감사합니다.