변경 이력을 남겨야 하는 요구사항이 있었습니다.CDC(Change Data Capture)를 활용해 처리할 수도 있었지만, 인력과 기술적인 제약으로 도입이 어려운 상황이었습니다. 이미 JPA를 기반으로 개발 중이었기 때문에, Hibernate가 제공하는 변경 감지 기능을 활용해 변경 이력을 남기는 방법을 고민하게 되었습니다. Hibernate에 DefaultFlushEntityEventListener를 통해 엔티티의 변경감지 로직을 손쉽게 확장할 수 있습니다. FlushEntityEvent 객체에는 영속성으로 관리되어 있는 Entity 정보와 propertyNames, propertyValues를 제공하며, 어떤 프로퍼티가 변경되었는지 dirtyProperties를 포함합니다. JPA의 구현체인 하이버네..
MySQL을 사용해서 개발을 하다보면 PK를 Auto-Increment로 잡는 경우가 많습니다. 그 이유는 MySQL에서 PK는 Clustered Index로 데이터를 저장하는 물리적인 순서를 PK의 순서로 정렬이 일어나기 때문에 Insert시 이득을 얻을 수 있으며, 대량의 데이터를 offset, limit를 사용해서 쿼리했을 때 범위 검색에 이득 또한 얻을 수 있습니다. Clustered Index 와 Non-Clustered IndexDatabase에서 index의 종류는 다양하지만 크게 Clustered Index와 Non-Clustered Index로 나뉜다.Cluster 사전적 의미군집화, 집속체, 무리, 밀접해있는 다수의 무언가를 총칭한다.Clustered Index: 실제 데이터uhan..
Kafka Streams DSL은 레코드의 흐름을 추상화한 개념으로 KStream, KTable, GlobalKTable이 존재합니다.이 개념들은 컨슈머, 프로듀서, 프로세서 API에서 사용되지 않고, 스트림즈 DSL 에서만 사용되는 개념입니다. KStream레코드의 흐름을 표현한 것으로 메시지 키와 메시지 값으로 구성되어 있습니다.카프카 컨슈머로 토픽을 구독하는 것처럼 KStream에 존재하는 모든 레코드가 출력됩니다. KTableKStream은 모든 레코드를 조회할 수 있지만 KTable은 유니크한 메시지 키를 기준으로 가장 최신 레코드를 사용합니다.Java Collection의 Map 자료구조처럼 토픽에 있는 데이터를 key-value store 처럼 사용하는 것 이라고 생각하면 된다.사용자 마지막..
@Async비동기 프로그램을 작성하기 위해서 복잡한 계산, I/O 작업 등 병렬로 처리하면서 시스템의 응답 시간을 개선하기 위해 혹은 리소스를 효율적으로 사용하기 위해 사용된다.스프링에서 간단하게 작성할 수 있도록 지원하는 애너테이션이다.Exception Handling@Async 메서드에서 발생하는 예외는 별도의 스레드에서 실행되기 때문에 호출자에게 전파가 되지 않는다.예외를 처리하기 위해서는 AsyncUncaughtExceptionHandler를 사용하여 예외를 처리해야 합니다. AsyncConfigurer를 구현하는 클래스AsyncConfigurerSupport를 사용한 확장은 deprecate 되었습니다. (참조)AsyncUncaughtExceptionHandler를 구현하는 클래스AsyncCon..
html을 파싱해서 썸네일 이미지를 추출해 Amazon S3에 저장해야 하는 일이 있었습니다.사이드 프로젝트 인 만큼 이미지 용량을 줄일 수 있으면 S3 비용도 아끼고 프론트 렌더링 속도 역시 개선되겠다고 생각이 들었고 resize와 webp 이미지 포맷을 사용하기로 결정했습니다. 이미지 읽기URL 정보를 통해서 이미지를 읽어와야 했었는데 Java에서 javax.imageio.ImageIO 클래스를 사용하면 쉽게 이미지를 읽고 쓸 수 있었습니다. URL 혹은 파일을 읽어서 처리가 가능합니다.BufferedImage image = ImageIO.read(new URL(이미지 주소));BufferedImage image = ImageIO.read(new File(이미지 저장 위치));java.awt.imag..