Image 생성 관련 최적화

@Entity
@Table (name = "product")
public class Product {
    @Embedded Id
    private ProductId id;
    private String name;
    @Convert (converter = MoneyConverter.class)
    private Money price;
    private String detail;
    @OneToMany ( cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true)
    @JoinColumn (name = "product_id")
    @Order Column (name = "list_idx")
    private List<image> images = new ArrayList<>();
    
    public void changeImages(List<Image> newImages) {
        images.clear();
        images.addAll(newImages);
    }
}
  • 상품에 이미지가 종속적임
    • 이미지는 상품의 생성과 삭제의 생명주기를 동일하게 가져간다.
    • 만약 이미지가 생성된 채로
      • clear() 를 수행하면
        • 사진이 4개면 4회의 select 가 수행되고
        • 4회의 delete 로직이 수행된다.
        • 상품 4000개를 삭제하는 경우
          • 4000 * (8) ⇒ 32000 회의 쿼리가 수행된다.

대안

  • 성능 향상을 위한 @Embeddable 활용
    • 엔티티 대신 @Embeddable 타입에 대한 컬렉션의 clear() 메서드 사용시
      • 한번의 delete 쿼리로 삭제 처리를 수행할 수 있다.

하지만,

  • 아래 같이
    • 상속 구조를 갖는 밸류타입이 사용되어 엔티티를 이용한 상속 매핑 구조로 처리된 경우
    • 별도의 분기없이, discriminator 로 처리되어, 로직 처리시 타입에 대한 분기처리가 필요가 없다.
    @Entity
    @Inheritance (strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn (name = "image_type")
    @Table (name = "image")
    public abstract class Image {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column (name = "image_id")
        private Long id;
    
        @Column (name = "image_path")
        private String path;
    
        @Temporal(TemporalType.TIMESTAMP)
        @Column (name = "upload_time")
        private Date uploadTime;
    
        protected Image () {}
    
        public Image (String path) {
            this.path = path;
            this.uploadTime = new Date();
        }
    
        protected String getPath() {
            return path;
        }
    
        public Date getUploadTime () {
            return uploadTime;
        }
    
        public abstract String getURL();
        public abstract boolean hasThumbnail();
        public abstract String get ThumbnailURL()
    }
    @Entity
    @DiscriminatorValue("II")
    public class InternalImage extends Image {
    }
    
    @Entity
    @DiscriminatorValue("EI")
    public class ExternalImage extends Image {
    }
    • 하지만, Embeddable 의 경우
    • 일일이 분기를 쳐야한다.
    @Embeddable
    public class Image {
        @Column(name "image_type")
        private String imageType;
    
        @Column(name = "image_path")
        private String path;
    
        @Temporal(TemporalType.TIMESTAMP)
        @Column(name private Date uploadTime;
    
        public boolean hasThumbnail ()) {
            // 성능을 위해 다형을 포기하고 ifelse로 구현
            if (imageType.equals("II")) { 
                return true;
            }
            else{
                return false;
            }
        }
    }
    • 위 케이스의 경우 다형성을 포기하게 되어 유지보수성에 문제가 있을 수는 있다.

Uploaded by N2T

'도메인주도개발' 카테고리의 다른 글

밸류를 이용한 ID의 매핑  (0) 2024.01.05
밸류 매핑 애그리거트  (0) 2024.01.05
애그리거트?  (0) 2024.01.02
애그리거트 간의 참조  (0) 2024.01.02
애그리거트를 팩토리를 사용하기  (0) 2024.01.02