[Spring] JPA 사용시 Entity Class 에 대한 고찰(Setter, Wapper Class)
https://myeongdev.tistory.com/16
예전에 공부하면서 Entity클래스에 대해서 생각해보고 글을 남긴적이 있다.
하지만, 예전에는 지식과 경험이 부족하여 매우 단순한 지식만 탐구하고 넘어가고 글을 써놓았다.
지금에 와서 다시 배우고 학습하며, 궁금증이 들어 글을 다시 작성하려고 한다.
Entity Class란?
실제 DB의 테이블과 매칭되는 클래스이다. 즉, DB의 테이블과 가장 유사하다고 볼 수 있다. 참고문서 hibernate reference docs
그렇다면 Entity Class 는 Data Access Object 로서, Spring MVC 패턴 중 Persistence Layer에 해당된다.
Persistence 란?
영속성(Persistence) 데이터를 생성한 프로그램이 종료되더라도 사라지지 않는 데이터의 특성을 말한다.
영속성을 갖지 않는 데이터는 단지 메모리에서만 존재하기 때문에 프로그램을 종료하면 모두 잃어 버리게 된다. 때문에 파일 시스템, 관계형 데이터베이스 등을 활용하여 데이터를 영구하게 저장하여 영속성을 부여한다.
이러한 역할을 하는 것이 Spring MVC 패턴에서 Persistence Layer 이다.
그렇다면 서론과 개념은 여기까지 정리를 하고, 문제점에 봉착했던 것들에 대해 작성해보려 한다.
Entity 클래스에서 Setter를 사용해도 되는 것인가?
위에 서술하였듯이, Entity클래스는 데이터베이스와 밀접한 연관을 맺어 데이터에 영속성을 부여하여, 데이터를 저장을 담당한다고 말 할 수 있다.
그렇다면 해당 클래스는 불변 속성을 갖아야 하는 것이 맞다고 볼 수있다.
왜냐하면 데이터 객체가 불변속성이 아니라면, 해당 데이터를 다른 계층 혹은 다른 접근 권한자가 해당 데이터를 조작할 수 있다는 것과 다를게 없다.
위의 말을 바탕으로 그렇다면 Entity 클래스에 Setter
를 열어두게 된다면?
해당 객체에 대한 불변성과 일관성이 무너지게 된다고 생각을 하였다.
그렇다면, 단순히 new Object()
처럼 new
연산자를 통해서면 데이터를 생성하고 변경하면 되는것인가? 라는 생각을 또 갖게 되었다.
일단 JPA(Java Persist API)
에서 데이터를 Insert, Update하는 구문은 save(S Entity)
로 동일하다.
즉, Entity 객체를 받아서 Insert와 Update를 모두 동작하게 된다.
그런데 이때 들었던 생각이 Entity클래스가 필드값이 무수히 많고, 변경이 가능하고, 변경이 되어야 되는 필드값은 한가지로 가정해 보겠다.
그렇다면 과연 update에 대해서 new
연산자만을 이용하여, 데이터를 업데이트 하는것이 맞을까?
그거에 대한 결로은 아니다 라고 생각 되었다.
먼저, new
생성자는 관례상 정말 객체를 생성하는데 필요한 역할을 담당하기 때문에, 생성자만을 이용하여 데이터를 관리하는 것은, 역할과 관례상 부담스러운 부분이 분명히 존재한다.
또한 수많은 필드를 생성자를 통해 생성하여 매모리에 선언한 뒤 다시 그 객체를 버린다는 것 자체가, 비용적으로 상당히 아깝다고 볼 수 있다.
가장 좋은 방법은 Setter를 열어두되 적절한 관리를 통해 데이터 객체에 대한 일관성을 해치지 않는 것이다. (무분별한 Lombok의 @Setter
은 정말 독이다. 그럴꺼면 Setter를 아예 쓰지말고 다른 방법을 고안하자.)
예를 들어 setter 메서드를 public이 아닌 private
로 접근 권한을 높이는 것이나 혹은, entity내부에 필드값 변경에 대한 메서드를 정의하여 메서드로만 접근 할 수 있도록 제한을 거는 것이다.
그러한 방법을 검색하며 예시를 알아보던 중 마음에 들었던 방벙이 있어 그것또한 작성해보려 한다.
@Setter를 사용하지 않고 Entity Class 데이터를 Update 하는 방법
Entity Class
@Entity
...
public void updateSomething(String value1, String value2, Long value3){
this.value1 = value1;
this.value2 = value2;
this.value3 = value3;
}
이때, 해당 메서드에 business로직이 존재하는 것은 별로 좋지 않다고 생각되어진다.
Entity class에 비지니스 로직을 둔다는 것이 책임과다를 불러 일으키고,
계층간의 경계가 흔들리게 된다고 생각되기에 비지니스 로직은 Service계층에서 처리를 한 뒤,
값만을 넘겨주어 위와 같이 처리하는 것이 좋다고 생각되어진다.
Service Class
@Service
...
public void updateById(Long id, SomethingDTO somethingDTO){
Something something = somethingRepositor.findById(id).orElseThrow(
()-> new NoSuchElementException());
something.updateSomething(somethingDTO.getValue1(), somethingDTO.getValue2(), somethingDTO.getValue3());
}
이때 findById()
로 갖고온 객체는 JPA의 영속성 관리 대상에 들어가기 때문에, EntityManager
가 관리하고 있는 상태이다.
그렇다면 findById()
로 가져온 객체는 EntityManager
의 관리 대상으로 1차 캐시에 저장되어 있는 상태이다.
이 후, Transaction이 종료(commit)될 때, 변경 감지(Dirty Checking)를 통해 변경된 데이터는 실제 DB에 저장되게 된다.
변경 감지는 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용되는 사항으로 EntityManager
에서 persist()
전인 비영속상태 혹은, detach()
상태인 준영속 상태는 적용되지 않는 다는 점을 알고 있어야 한다.
Transaction을 commit()
하게 되면, EntityManager
에서 내부적으로 먼저 flush()
를 동작하여 변경 감지를 통해 영속성 컨텍스트에 있는 모든 엔티티를 스냅샷과 비요하여 수정된 엔티티를 찾고, 해당 엔티티를 쓰기 지연 SQL 저장소에 보관 한 후, 실제 flush
를 동작하여 DB에 변경된 데이터를 저장 한 후 Transaction이 종료 되는 과정인 것이다.
이것이 JPA의 EntityManager을 통한 영속성 데이터 관리의 일련 과정이다.
이렇게 이 글에 대한 주제인 Entity 클래스의 Setter 메서드는 제한적으로 사용해도 되며, 세심한 관리가 필요하고, 무분별한 Setter는 안쓰니만 못하다.
출처
'1.프로그래밍 > Java' 카테고리의 다른 글
[Spring Security] SessionManagement (0) | 2023.01.20 |
---|---|
[Spring] Spring 비밀번호 암호화 SHA-256 ~ BCryptPasswordEncoder(MessageDigest, SHA-256, BCryptPasswordEncoder) (0) | 2022.12.07 |
[Spring] Spring MockMvc 정리 (REST API 테스트, Multipart/form-data 테스트) (0) | 2022.11.21 |
[SpringBoot] IntelliJ Thymeleaf 자동 리로드(Live reload) (1) | 2022.09.25 |
[Spring Boot] Spring Data JPA 기초(코드로 배우는 스프링 부트 웹 프로젝트 ) (2) | 2022.09.25 |