JPA UPDATE & 더티체킹, 영속성 컨텍스트

김형민·2021년 10월 15일
0


UPDATE 기능을 하는 두개의 코드를 비교해보자

밑의 두 코드를 보면 ID로 user테이블에서 유저를 찾고 해당유저의 password & eamil을 수정해준다.

두 코드의 차이를 보면
각각 코드에 없는 것을 찾아보면
첫 번째는 userRepository.save(user);
두 번째는 @Transactional
이렇게 있다. 무슨 차이점 일까??

1번 코드

	// 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;
	}

2번 코드

	@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에 가서 찾지않고 영속성 컨텍스트에서 들고온다! (부하가 덜하다)

UPDATE의 경우엔?

위의 코드 처럼 2가지 경우로 나눌 수 있다.

1번

DB에서 가져와서 영속화를 시킴 > user값을 set > 영속화된 object(user)의 값과 비교(같은 아이디(key) 라면) > save를 호출해 set된 값만 변경

2번(더티 체킹)

@Transactional을 사용해 컨트롤러 코드가 끝날때까지 트랜잭션이 실행된다.

함수 종료시 자동으로 commit이 된다.
그리고 update가 되는 이유는

ex) 2번 user를 update하는 경우 db에서 영속성 컨텍스트로 가져온다(영속화) > 값을 set > 코드 종료 후 commit > 원래 처음 가져온 user object와 비교를 해 변경됨을 인식함 > 컨트롤러 종료시 update실행

더티 체킹 코드에서 update를 실행하는 이유는 user object에 값이 변경됨을 감지해서!

profile
항해 중인 개발자

0개의 댓글