[SpringBoot JPA 활용 웹 애플리케이션 개발 : 수정(변경감지, Merge)]

Han Gyul Kang·2022년 4월 17일
0

Inflern_Spring_JPA

목록 보기
11/12

1. 보안 취약점

ID 값이 수정되어서 넘어올 수 있음(보안 취약점)
유저가 해당 아이템에 대한 권한이 있는지 없는지 체크하는 로직이 서버에 있어야 한다.

데이터 수정을 위해서 EntityManager 객체의 merge 메서드를 사용하지만
실무에서는 사실 거의 사용하지 않는 기능이다.

2. 변경감지와 병합(merge)

반드시 완벽하게 이해해야하는 과제

[변경감지(= dirty checking)]

JPA에서 Transaction 안의 영속성 Entity의 데이터가 변경되면 변경을 감지해서 데이터를 update 함

내가 이해하기 쉽게 말하자면 Spring MVC에서 Transaction 안에 돌아가는 프로세스 중
DTO 클래스에 setter로 데이터 변경만 해줘도 Tsansaction이 종료되는 시점에
update 쿼리가 자동 실행되는 것 같은 느낌이라고 할 수 있을 것 같다...

Transaction commit 시점에 flush를 날리면서 데이터를 update 함 update를 따로 날릴 필요가 없음
해당 내용에 대해서는 아래에서 부가 설명 있음

[준영속 엔티티 = 영속성 컨텍스트가 더 이상 관리하지 않는 엔티티]

데이터베이스에 저장 되고 불러와진 데이터는 데이터베이스를 한 번 다녀왔기 때문에 식별자가 이미 존재한다.
이럴 경우 준영속 엔티티(=식별자를 기존에 이미 가지고있는 경우)가 된다.

JPA가 더 이상 관리하지 않음
dirty checking을 하지 않음
즉, new 로 Entity를 새로 생성하고 setter를 사용해서 데이터를 변경해도 JPA가 확인하지 않음

[준영속 엔티티를 수정하는 두 가지 방법]

  • 변경 감지 기능 사용
  • 병합(merge) 사용

2.1. 변경 감지

  • Service에서 Update 비즈니스 로직 메서드에 Transactional을 걸어주면 Commit이 되는 시점에 flush()를 진행
  • Update 비즈니스 로직에서 식별자로 데이터를 가져와 Entity에 넣어주면 영속상태의 데이터를 가져온 것이 됨
  • 해당 Entity 객체에 화면에서 넘어온 데이터로 데이터를 set하면 영속성 Entity의 데이터에 변화를 준 것임
  • flush()가 진행되고 JPA의 영속성 컨텍스가 변경 된 엔티티를 체크하게 됨(=Dirty Checking)
  • 변경 감지(Dirty Checking)를 통해 데이터를 변경 함

[요약]
트랜잭션 안에서 엔티티를 다시 조회, 변경할 값 선택
-> 트랜잭션 커밋 시점에 변경 감지(Dirty Checking)가 동작해서 데이터베이스에 update SQL을 실행

트랜잭션 안에서 영속성 엔티티를 조회해야하고, 엔티티의 데이터를 직접 변경해야 한다.

그래야 트랜잭션 커밋 시점에 데이터 변경이 일어난다.

2.2. 병합 사용(이론만 알고 있고 사용은 하지 말 것)

병합(merge)은 준영속 상태의 엔티티를 영속 상태로 변경할 때 사용하는 기능이다.

[이론]
merge()를 실행한다.
파라미터로 넘어온 준영속 엔티티의 식별자 값으로 1차 캐시에서 엔티티를 조회한다.
없으면 데이터베이스에서 엔티티를 조회하고 1차 캐시에 저장한다.
엔티티의 값을 변경 된 값으로 전부다 바꾸고 해당 엔티티를 반환한다.
단, 파라미터로 넘어온 준영속 엔티티가 영속성 엔티티로 변하진 않는다.

[주의]
변경 감지(=Dirty Checking)를 사용해서 데이터를 변경하면 엔티티에서 변경된 값만 Update 한다.
병합을 사용해서 데이터를 변경하면 엔티티의 모든 속성이 변경된다.

예를들어 name 필드만 변경할 수 있는 화면에서 name을 제외한 나머지는 모두 null값으로 넘어와 setting이 되버린다면 식별자에 해당하는 데이터의 이름만 변경되고 나머지 필드는 모두 null로 Update해버린다. = 지옥행 열차
즉, merge는 선택을 할 수 있는 개념이 아니다.

[예시]
가격은 한 번 책정되면 변경하지 않기로 정한 상태에서 merge를 사용하게 되면
사용자가 화면에서 데이터를 변경 시 가격 값을 보내지 않는다? database에 가격이 null로 update 된다.
다시 말해 엔티티의 필드가 10개인데 수정은 4개만 하는 경우가 발생하면 나머지 필드는 update를 막기 위해 쓸데없는 로직이 늘어날 수 있다(=관리포인트 다량 발생).

3. 결론

귀찮더라도 merge보다는 변경 감지를 사용해야한다.
merge는 한 번에 모두 update, 변경 감지는 정확하게 선택만 해서 update


[추가 조언]

  • 엔티티를 어설프게 컨트롤러에서 사용하지 말자
  • 트랜잭션이 있는 서비스 계층에 식별자를 명확하게 전달하자

profile
피아노 치는 개발자

0개의 댓글