목차

    개요

    김영한님의 JPA 책 중에 코드에서의 객체와 데이터베이스 사이의 패러다임 불균형을 JPA가 해결해준다라는 내용이 있습니다. 그에 관한 예시 중 상속에 관한 이야기가 있었습니다. '상속은 객체의 대표적인 속성인데 데이터베이스로 표현하려면 불편해진다. 이러한것들을 JPA가 해결해준다.' 라는 내용이었습니다. 이 때 들어준 예시 코드가 JPA를 이용하여 직접 등록해주는 방식 등 정석적인 방법처럼 보였는데 현재 저는 데이터베이스에 저장할 객체는 @Entity를 사용해주고 JpaRepository를 상속시켜 DB와 연동시키는 방법을 사용합니다. 이러한 과정에서 현재 제가 사용하는 방법에서도 상속을 이용한 뒤 DB에 저장시키는 방법론이 동일하게 적용되는지 궁금하여 실험을 해보았습니다.

    (빠른 실험을 위해 만든 코드이기에 DTO 클래스도 없고 db 생성 시 데이터 정확한지 확인하는 과정도 없습니다.)

     

    실험 시작

    우선 책의 예시대로 부모 클래스를 만들어준 뒤 자식 클래스를 만들었습니다.

    @Entity
    @Getter
    abstract class Item {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        Long id;
        String name;
        int price;
    }
    @Entity
    @NoArgsConstructor
    @Getter
    public class Album extends Item{
        String artist;
    }
    @Entity
    public class Movie extends Item{
        String director;
        String actor;
    }

     

    Album 클래스만 통해서 테스트 해볼 것이기 때문에 Album과 관련하여 Repository, Service, Controller를 생성했습니다.

    public interface AlbumRepository extends JpaRepository<Album, Long> {
    }
    @Service
    @RequiredArgsConstructor
    public class AlbumService {
    
        private final AlbumRepository albumRepository;
    
        public Album createAlbum(Album album) {
            return albumRepository.save(album);
        }
    
    }
    @RestController
    @RequiredArgsConstructor
    public class AlbumController {
    
        private final AlbumService albumService;
    
        @PostMapping("/album")
        public ResponseEntity postAlbum(@RequestBody Album album) {
            albumService.createAlbum(album);
            return new ResponseEntity(HttpStatus.CREATED);
        }
    
    }

     

    위 과정들을 진행한 후, 코드를 실행하여 DB를 확인해보았습니다.

     

    문제 발생

    확인해본 DB 테이블의 결과는 신기했습니다.

    '오 진짜로 영한님 책에서 나온 것처럼 DTYPE이 생기네.'

    하지만 문제가 발생했음을 알 수 있었습니다.

    '어? 책에서는 ITEM 테이블 따로 ALBUM 테이블 따로 생성되고 필요 데이터 조회할 때 Join 된다고 쓰여져있었는데? 왜 ITEM 테이블만 생성되고 한 테이블 안에 모든 칼럼이 들어가있지? 우선 값을 넣어보자'

     

    '이렇게 되면 상황에 따라 null이 많아질텐데 정규화에 문제 생기지 않나?'

    그래서 문제의 원인을 찾아보았습니다.

     

    문제 해결

    문제 해결법은 @Inheritance라는 애너테이션의 존재였습니다.

    @Inheritance를 부모 클래스에 달아주고 상속 전략을 Joined로 선택해주면 모든게 해결되는거였습니다.

    @Entity
    @Getter
    @Inheritance(strategy = InheritanceType.JOINED)
    abstract class Item {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        Long id;
        String name;
        int price;
    }

    이렇게 하면 각 Entity가 각 테이블로 잘 쪼개어진 것을 확인하실 수 있고요.

    앞선 예시와 동일한 예시를 넣어주면 아래와 같이 깔끔하게 들어가는 것을 확인하실 수 있습니다.

     

    문제는 문제가 아니었음을

    앞선 설명들을 보시면 한 테이블에 모든게 나오는 것이 문제고 깔끔하게 나오는게 정답처럼 써놓았습니다.

    하지만 해당 해결 과정을 위해 참고한 블로그를 공부하다보니 각각의 장단점과 함께 전략을 활용하는 방법이었음을 알게 되었습니다.

    상속 전략을 정하는 방식과 각 장단점 그리고 DTYPE 이름도 정할 수 있음을 공부하고 싶으신 분들은 아래의 Reference 블로그 주소를 참조해주시면 좋을 것 같습니다.

     

     

    reference

    https://jaime-note.tistory.com/381