◼︎ 환경
- Model : MacBook Pro (14-inch, 2021)
 - CPU : Apple M1 Pro
 - MENORY : 16GB
 - DISK : 512 GB SSD
 - OS : macOS 13.2.4 (22F66)
 - TOOLS : Visual Studio Code, Java 11, Gradle, Docker
 - Version Control : GitHub
 - Programming Language : Java
 - Framework : Spring Boot 2.7.12
 - DBMS : MySql 8.0.33
 
문제
첨부파일 데이터를 데이터베이스에 저장하는 구조의 첨부파일 모듈을 아래와 같이 구성하고 있다.
첨부파일 엔터티 클래스는 아래와 같이 ❶ LocalAttachment 와 ❷ LocalAttachmentData로 구성되어 있으며 이들은 one-to-one 으로 매핑되어 있다.
 @Data
 @NoArgsConstructor
 @Entity
 @Table(name = "AC_UI_ATTACHMENT")
 public class LocalAttachment implements Attachment, PropertyAware {
    @Id // tell persistence provider 'id' is primary key
    @Column(name = "ATTACHMENT_ID", nullable = false)
    @GeneratedValue( // tell persistence provider that value of 'id' will be generated
        strategy = GenerationType.IDENTITY // use RDBMS unique id generator
    )
    private long attachmentId;
    @Column(name = "OBJECT_TYPE", nullable = false)
    private int objectType;
    @Column(name = "OBJECT_ID", nullable = false)
    private long objectId;
    @Column(name = "CONTENT_TYPE", nullable = false)
    private String contentType;
    @Column(name = "FILE_NAME", nullable = false)
    private String name;
    @Column(name = "FILE_SIZE", nullable = false)
    private int size;
    @Transient // tell persistence provider ignore 'downloadCount' field.
    private int downloadCount = 0;
    @Transient // tell persistence provider ignore 'tags' field.
    private String tags;
    @JsonIgnore
    @Transient // tell persistence provider ignore 'inputStream' field.
    private InputStream inputStream;
    @JsonIgnore
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY )
    @JoinColumn(name = "ATTACHMENT_ID")
    private LocalAttachmentData data;
    @Transient // tell persistence provider ignore 'sharedLink' field.
    private SharedLink sharedLink;
    @CreatedBy
    @OneToOne(targetEntity = LocalUser.class)
    @JoinColumn(name = "USER_ID", nullable = false)
    @JsonDeserialize(using = JsonUserDeserializer.class)
    private User user;
    @CreatedDate
    @Column(name = "CREATION_DATE", updatable = false)
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
    private Date creationDate;
    @LastModifiedDate
    @Column(name = "MODIFIED_DATE")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
    private Date modifiedDate;
    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "AC_UI_ATTACHMENT_PROPERTY", joinColumns = {
    @JoinColumn(name = "ATTACHMENT_ID", referencedColumnName = "ATTACHMENT_ID") })
    @MapKeyColumn(name = "PROPERTY_NAME")
    @Column(name = "PROPERTY_VALUE")
    private Map<String, String> properties;
 }
 @Data
 @Entity
 @Table(name = "AC_UI_ATTACHMENT_DATA")
 @NoArgsConstructor
 @AllArgsConstructor
 public class LocalAttachmentData {
    @Id
    @Column(name = "ATTACHMENT_ID")
    private Long attachmentId;
    @Lob
    @Column(name = "ATTACHMENT_DATA")
    private Blob blob;
 }
이경우 문제가 되는 것은 LocalAttachmentData 는 Blob 데이터 이기 때문에 데이터 크기에 따라 목록을 조회하는 경우 성능 저하 이슈가 발생하게 된다. FetchType.LAZY 옵션을 사용하여 보았지만 성능에 개선은 없었다.
문제 해결
목록을 조회할 때 바이너리 데이터를 같이 조회하지 않도록 하기 위하여 one-to-one 매핑을 제거하고 LocalAttachment 에 해당하는 ❷ LocalAttachmentData 를 별도의 Repository 을 사용하여 처리하는 것으로 변경하였다. 
    @JsonIgnore
    @Transient
    //@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY )
    //@JoinColumn(name = "ATTACHMENT_ID")
    private LocalAttachmentData data;
엔터티간의 매핑을 제거하였기 때문에 저장시 LocalAttachmentData 을 처리하는 로직을 추가할 필요가 있었다.
  attachmentRepository.save(attachmentToUse ); 
  if( attachmentToUse.getData() != null){
     LocalAttachmentData data = attachmentToUse.getData();
     data.setAttachmentId(attachmentToUse.getAttachmentId());
     attachmentDataRepository.save(attachmentToUse.getData()); 
   }
댓글 없음:
댓글 쓰기