본문 바로가기

스프링 부트

(30)
[Spring Batch] JpaPagingItemReader + JpaItemWriter를 사용했 때겪었던 문제점 (2) (수정중) 다시한번 언급하지만, 이 글의 전제는 '애초에 이렇게 배치를 구현하면 안된다'로, JpaPagingItemReader, JpaItemWriter를 가지고 이것 저것 실험하면서 경험한 내용을 정리한 글이다. 앞 글에서 아직 다 다루지 못한 문제가 남아있다. 바로 "마지막 청크는 5개 쿠폰에 대한 history는 정상적으로 한개씩만 쌓이고 있다" 라는 것이다. (어느정도 감이 왔을 수도 있지만...) 이에 대한 원인은 다른 예제로 설명해보려 한다. JpaItemWriter에서 Dirty Checking으로 엔티티 변경사항을 DB에 반영할 때 문제점 앞 글에서 발생한 자식엔티티 중복 저장에 대한 문제는 결국 reader와 writer에서 서로 다른 entityManager를 사용하고 있었기 때문이었..
[Spring Batch] JpaPagingItemReader + JpaItemWriter를 사용했 때겪었던 문제점 (1) 최근 배치를 짜고 운영하다가 참으로 이상한 현상을 겪었는데, 이를 JpaPagingItemReader, JpaItemWriter의 내부 동작과 함께 원인을 정리해보려 한다. (aka. 나의 삽질 기록) 내 삽질 기록을 정리한 글을 통해 말하고자 하는 내용을 미리 정의하고 넘어가자면, 배치 reader로 조회한 엔티티를 그대로 사용하지말고 특정 필요한 값만 dto로 뽑아쓰는 방식을 취하자이다 (엔티티의 수정 x). 이 글은 내가 배치 reader로 조회한 엔티티 그대로를 직접 수정, dirty checking을 이용하다 생긴 문제로, 애초에 이렇게 구현하면 안된다가 전제로 깔린다. 그냥 배치에서 엔티티를 지직 볶고 하다가 깨닫게 된 몇가지 내용들을 정리한 글로 봐주길. 문제상황 예시 먼저 Coupon(쿠폰..
@Transactional 메서드에서 다른 클래스의 @Async 메서드를 호출하면? (feat. 트랜잭션과 스레드) 서로 다른 스레드 간 트랜잭션 공유를 초점으로, 스프링이 트랜잭션을 어떻게 관리하는지 아주 일부분 관찰해본 글입니다. (참고) 아주*1000 간단한 테스트 환경 // main에 @EnableAsync @Transactional @Service class TxService( private val testEntityRepository: TestEntityRepository, private val innerService: AsyncService ) { fun saveOneAndCallException() { logger.info("[TxService][saveOneAndCallException] 호출. Thread id: ${Thread.currentThread().id}") // 테스트 엔티티 1 save ..
JPA Auditing과 제대로 알아야 할 @PreUpdate JPA Auditing? 서비스를 운영하다보면 데이터가 변경되었을 때 누가 값을 변경했고, 언제 변경했는지를 남겨야할 때가 있다. Spring Data Jpa 에서는 이에 대해 어노테이션으로 편리하게 Audit(감시) 기능을 제공해주고 있다. 엔티티를 영속성 컨텍스트에 저장하거나 조회를 수행한 후 수정하게 되면 이에 대한 변경 시간 등을 자동으로 매핑하여 데이터베이스에 반영해주게 된다. 사용 방법 1. @EnableJpaAuditing 추가 해당 어노테이션을 main 메서드가 있는 애플리케이션 클래스에 추가한다. @EnableJpaAuditing @SpringBootApplication public class NoltoApplication { public static void main(String[] a..
@DirtiesContext로 무거워진 인수 테스트 시간을 줄이는 실험을 해봅시다 인수 테스트 - @DirtiesContext 를 제거하자! 각각의 인수 테스트는 테스트 간 격리성을 가져야 하는데, RestAssured 테스트는 테스트 전용 @Transactional을 사용하지 못한다. 즉 데이터 관련 컨텍스트가 공유되고, 이 데이터 베이스를 각각의 테스트마다 초기화해주기 위해 지금껏 당연히 @DirtiesContext를 사용해왔다. 하지만 @DirtiesContext를 사용할 경우 매번 컨텍스트를 새로 로드하기 때문에 인수테스트만 어마무시한 시간이 들게 된다. 실제로 놀토 프로젝트도 인수테스트를 수행하는데만 (사양마다 다르겠지만) 내 맥북 기준 2분정도가 소요되었다. 결국 인수테스트에서 우리가 현재 원하는 것은 데이터의 격리성이고, 이를 위해 매번 빈들을 초기화 해주는 것이었다. 즉..
[JPA] 기본 키 생성 전략과 각 전략의 차이 - GenerationType JPA에서 Entity 객체를 정의할 때 @Id 속성을 함께 정의하여야 한다. 이 Id를 정의할 때에는 직접 할당하는 방법과 자동 생성하는 방법이 있다. 직접 할당하는 방법 @Id 어노테이션만으로 id를 지정한다. 자동 생성 @Id와 @GeneratedValue를 같이 사용한다. GenerationType 옵션으로 전략을 지정한다. GenerationType 종류 TABLE 특정 벤더에 의존적이지 않다. 시퀀스 테이블을 만들어서 데이터베이스 시퀀스를 흉내낼 Id를 할당한다. 이 전략을 사용할 시, jpa ddl auto 설정이 되어 있지 않았다면 해당 시퀀스 테이블 생성이 선행이 되어야한다. @TableGenerator(테이블 생성 어노테이션)과 함께 사용할 수 있다. 만약 jpa ddl auto 설정이..
application.properties VS application.yml 그리고 YAML을 사용하면서 겪은 문제점 application.properties 설정 Spring Boot는key-value 형식을 사용하는application.properties파일설정 값들을 가져와 쓸 수 있다. spring.datasource.url=jdbc:h2:dev spring.datasource.username=SA spring.datasource.password=password 각 라인은 단 하나의 key-value로 이루어져있다. 닷(.)을 이용해 계층적 구조를 이룰 수 있다. Placeholders 값을 지정할 때, ${} 을 사용해 다른 환경 변수의 값을 참조할 수 있다. app.name=MyApp app.description=${app.name} is a Spring Boot application List 하나의 속성에 ..
S3를 사용하는 환경에서 LocalStack을 통한 통합 테스트 놀토는 이미지 저장소로 AWS의 S3를 사용한다. 하지만 S3에 대한 쓰기 작업은 우테코 측해에 권한을 부여한 EC2에서만 가능했으며 accesskey와 secretkey도 받을 수 없었기 때문에, 로컬 환경에서는 S3를 사용하는 서비스에 대해서 테스트를 진행할 수 없었다. AWS의 S3를 이용하는 서비스단을 통합 테스트하는 방법으로 LoacalStack을 이용하는 방법을 제시해줬는데, 이를 사용하는 통합테스트를 진행한 과정들을 기록한다. Localstack? LocalStack provides an easy-to-use test/mocking framework for developing Cloud applications. It spins up a testing environment on your loc..