update 테스트
id와 username은 수정하지 않고, password와 email만 수정할 수 있도록 한다.
기존에 Insert 테스트에서는 폼태그로 데이터를 받아왔는데 이번에는 JSON 데이터를 받는 방식으로 테스트 해본다.
JSON 데이터를 받아올 때에는 @RequestBody를 사용한다. @RequestBody를 사용하면 json 데이터를 요청했을 때 MessageConverter의 Jackson 라이브러리가 Java Object로 변환해서 받아준다.
// id와 username은 수정 X, password, email만 수정
// GetMapping과 주소가 겹칠 것 같지만 구분한다.
@PutMapping("/dummy/user/{id}")
public User updateUser(@PathVariable int id, @RequestBody User requestUser) {
System.out.println("id : " + id);
System.out.println("password : " + requestUser.getPassword());
System.out.println("email : " + requestUser.getEmail());
// DB 저장
requestUser.setId(id);
requestUser.setUsername("honal");
userRepository.save(requestUser);
return null;
}
id가 1인 회원의 정보를 수정해보자. PUT으로 접속하고 JSON 데이터를 받아서 수정할 때에는 form이 아닌 raw의 JSON으로 해줘야 한다!!
DB에 들어가보면 다음과 같이 바뀌어있다. 기존의 id 1번을 찾아서 덮어쓰기 해주는 너낌.
하지만 save()라는 함수를 쓰게 되면 id를 전달하지 않으면 insert를 해주고, id를 전달하면 해당 데이터가 있으면 update, 없으면 insert를 해준다. save()는 거의 Insert할 때 쓰고, 위처럼 코딩하면 기존 값들이 null값으로 채워진다.. 그래서 update할 때에는 save()를 거의 쓰지 않는다.
save()를 통해서 update 할 경우
@PutMapping("/dummy/user/{id}")
public User updateUser(@PathVariable int id, @RequestBody User requestUser) {
User user = userRepository.findById(id).orElseThrow(()->{
return new IllegalArgumentException("수정에 실패하였습니다.");
});
user.setPassword(requestUser.getPassword());
user.setEmail(requestUser.getEmail());
userRepository.save(user);
return null;
}
이렇게 하면 null로 덮여쓰여지지 않고 기존의 데이터를 일부분만 수정할 수 있다.
@Transactional
userRepository.save(user); 코드를 주석처리 한 후 updateUser 메소드에 @Transactional 어노테이션을 붙인 후 update를 시도해보자. save()를 호출하지 않아도 update가 잘 이루어진 것을 볼 수 있다. 이것을 더티 체킹이라고 하고, 앞으로 update는 이러한 방식으로 할 것이다.
왜 그럴까?
Controller에서 User 객체를 하나 생성 후 save를 통해 DB에 저장하는 과정과 비교하며 알아보자
save를 호출하게 되면 먼저 JPA 영속성 컨텍스트의 1차 캐시에 영속화 시킨다.
그 후 1차 캐시에서 DB로 flush라는 과정을 통해 밀어넣는다. flush는 원래 현재 창고를 비우고 다른 창고로 옮기는 과정인데 여기에선 1차 캐시를 비우지 않는다. 나중에 Controller에서 Select를 했을 때 1차 캐시에 영속화되어 있는 지 확인 후 그대로 들고올 때 활용한다. 실제 DB에 접근하지 않고도 응답할 수 있어서 부하를 덜어준다.
2번 데이터의 password를 Update 하는 과정을 살펴보자.
먼저 Select를 통해 2번 데이터를 DB에서 꺼내온다. 그 후 JPA 영속성 컨텍스트의 1차 캐시에 영속화시킨다. 그 후 그 2번 데이터 오브젝트를 컨트롤러로 들고온다. 그 후 값을 변경하고 save를 호출한다.
save를 호출하게 되면 아까처럼 영속화할 필요 없이 이미 1차 캐시에 영속화된 2번을 변경된 값으로 update 시킨다. 그 후 다시 flush를 통해 DB의 값을 Update 시키는 것이다.
@Transactional을 사용하면?
@Transactional의 어노테이션을 통해 DB 트랜잭션이 시작되고 컨트롤러가 종료될 때 트랜잭션이 종료된다. 함수 종료 시 자동 커밋을 해주는데 이 때 변경을 감지해서 DB에 update를 실행해준다. 이것을 더티체킹이라고 한다. 이때문에 save를 호출하지 않고도 DB가 update된 것이다.
출처 : https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9
'Spring > Blog 만들기 with SpringBoot' 카테고리의 다른 글
스프링 기본 파싱 전략과 JSON 통신 (0) | 2022.06.13 |
---|---|
delete 테스트, Exception 처리 (0) | 2022.05.16 |
selecte 및 paging 테스트 (0) | 2022.05.10 |
insert 테스트, enum 사용법 (0) | 2022.05.10 |
JSON (0) | 2022.05.10 |