UPDATE 기능을 하는 두개의 코드를 비교해보자
밑의 두 코드를 보면 ID로 user테이블에서 유저를 찾고 해당유저의 password & eamil을 수정해준다.
두 코드의 차이를 보면
각각 코드에 없는 것을 찾아보면
첫 번째는 userRepository.save(user);
두 번째는 @Transactional
이렇게 있다. 무슨 차이점 일까??
// email, pw
// json 데이터를 받기 위해 @RequestBody 필요
@PutMapping("/dummy/user/save/{id}")
public User updateUser (@PathVariable int id, @RequestBody User requestUser) { // json데이터를 => java object로 변환해서 받음
System.out.println("id"+id);
System.out.println("password"+requestUser.getPassword());
System.out.println("email"+requestUser.getEmail());
// 수정하기 전에 id로 user를 찾는다(영속화)
User user = userRepository.findById(id).orElseThrow(()-> {
return new IllegalArgumentException("수정실패");
});
// 받아온 데이터로 set
user.setPassword(requestUser.getPassword());
user.setEmail(requestUser.getEmail());
// 이렇게 해줘야 null 값인 부분은 빼고 update(save)실행
// save함수는 id를 전달하지 않으면 insert
// id를 전달해주고 해당 데이터가 있으면 update
userRepository.save(user);
return null;
}
@Transactional
@PutMapping("/dummy/user/{id}")
public User updateUser2 (@PathVariable int id, @RequestBody User requestUser) { // json데이터를 => java object로 변환해서 받음
System.out.println("id"+id);
System.out.println("password"+requestUser.getPassword());
System.out.println("email"+requestUser.getEmail());
// 수정하기 전에 id로 user를 찾는다(영속화)
User user = userRepository.findById(id).orElseThrow(()-> {
return new IllegalArgumentException("수정실패");
});
// 받아온 데이터로 set
user.setPassword(requestUser.getPassword());
user.setEmail(requestUser.getEmail());
return null;
}
jpa에는 영속성 컨텍스트라는 큰 친구가 있다.
만약 insert를 실행한다고 하면 컨트롤러에서 user객체를 하나 만든다.
그리고 save를 하면 먼저 영속성 컨텍스트의 1차 캐쉬로 쌓인다(영속화)
그리고 쌓인 캐쉬(객체)를 DB에 넣어준다(flush)
Controller > 영속성 컨텍스트 > DB
flush를 밥상머리 교육으로 설명하자면...
작은 창고에서 큰 창고로 옮기는 작업? 이라고 할 수 있다..
작은 창고는 계속 물건을 받으려면 비워줘야 하니까..
그러나, JPA에서 영속화 된 데이터는 계속 영속성 컨텍스트에 남아있다..! 그리고 SELECT 코드를 실행하면 굳이 DB에 가서 찾지않고 영속성 컨텍스트에서 들고온다! (부하가 덜하다)
위의 코드 처럼 2가지 경우로 나눌 수 있다.
DB에서 가져와서 영속화를 시킴 > user값을 set > 영속화된 object(user)의 값과 비교(같은 아이디(key) 라면) > save를 호출해 set된 값만 변경
@Transactional을 사용해 컨트롤러 코드가 끝날때까지 트랜잭션이 실행된다.
함수 종료시 자동으로 commit이 된다.
그리고 update가 되는 이유는
ex) 2번 user를 update하는 경우 db에서 영속성 컨텍스트로 가져온다(영속화) > 값을 set > 코드 종료 후 commit > 원래 처음 가져온 user object와 비교를 해 변경됨을 인식함 > 컨트롤러 종료시 update실행
더티 체킹 코드에서 update를 실행하는 이유는 user object에 값이 변경됨을 감지해서!