목록분류 전체보기 (102)
영호
들어가면서 평소 길어진 빌드 시간을 개선하기 위해 방법을 찾아보다가 Junit 병렬 실행에 대해 알게됐고 이를 적용해봤습니다. 이 글에서는 Junit 병렬 실행 설정을 통해 테스트 실행 시간을 줄인 방법에 대해서 작성해보려고 합니다. 설정 방법 junit-platform.properties 파일을 생성해서 병렬 실행 설정을 해주면 됩니다. junit.jupiter.execution.parallel.enabled=true junit.jupiter.execution.parallel.mode.classes.default = concurrent junit.jupiter.execution.parallel.config.strategy=fixed junit.jupiter.execution.parallel.config..
들어가면서 이번 글에서는 프로젝트를 진행하며 엔티티 구조를 변경해 로직 복잡성을 낮추고, 쿼리를 개선한 경험을 작성하려고 합니다. 상황 및 엔티티 구조 설명 상황 설명 저희 프로젝트는 개인 카페의 쿠폰을 한 곳에서 관리해주는 서비스 입니다. 여기에 더불어 카페 사장님은 쿠폰의 디자인, 쿠폰에 찍히는 스탬프의 위치를 모두 커스텀 할 수 있습니다. 그리고 발급된 쿠폰은 발급 당시의 이미지 정보를 토대로 보여지게 됩니다. A쿠폰 발급 후 사장님이 카페의 쿠폰 이미지를 변경해도 A쿠폰은 발급 당시의 이미지로 보여집니다. 즉, 쿠폰은 발급 당시 이미지, 스탬프 위치 정보를 적용합니다. 엔티티 구조 설명 위 요구사항을 만족하기 위해 카페 별 쿠폰 정보를 저장하는 복사 테이블을 만들었습니다. 그 이유는 당시 저희는 ..
들어가면서, 우테코 프로젝트에서 @TransactionalEventListener 를 사용할 때 READ 는 되는데 CUD 쿼리가 발생하지 않는 문제를 겪었다. 그래서 이에 대한 원인에 대해 공부한 과정을 정리 해볼 예정이다. 트랜잭션 생성 과정과 커밋 과정 REQUIRED, REQUIES_NEW 옵션의 트랜잭션 생성 과정 물리 트랜잭션, 논리 트랜잭션 커밋 과정 각각에 대한 자세한 내용은 링크에 있습니다. 간단하게 요약하자면, 아래와 같은 흐름으로 진행됩니다. 트랜잭션 생성 시 스레드 로컬에 트랜잭션 관련 자원이 있으면 기존 트랜잭션이 있다고 판단. REQUIRED 옵션은 새로운 트랜잭션을 논리 트랜잭션으로 생성 REQUIRES_NEW 는 스레드 로컬에 자원이 있어도 새로운 물리 트랜잭션으로 생성 이후..
들어가면서, 프로젝트 도중, 아래의 요구사항을 구현하면서 @TransactionalEventListner 를 사용해 기존 코드의 문제점이었던 코드의 유지보수성과 불필요한 로직의 트랜잭션을 제거한 과정을 기록하려고 한다. 스탬프 적립이 정상적으로 완료되면, 슬랙으로 알림을 보낸다. 알림 발송에 실패해도 스탬프 적립이 롤백되어선 안된다. 기존 코드 @Transactional public void createStamp(StampCreateDto stampCreateDto) { // 스탬프 적립 전 여러 검증 코드 coupon.accumulate(earningStampCount); // 슬랙 API 호출 } 기존 코드의 문제점 기존 코드는 아래와 같은 문제점이 있다고 판단했다. 외부 API 와 비즈니스 로직이 ..
들어가면서, 트랜잭션 전파 옵션에는 REQUIRED, REQUIRES_NEW 등등이 있다. 그 중에서 이번에는 REQUIRED, REQUIRES_NEW 옵션일 때 트랜잭션 생성 과정에 대해 알아볼 예정이다. REQUIRED 는 어떻게 기존 트랜잭션이 존재하면서 해당 트랜잭션에 참여하고, 없으면 새로운 트랜잭션을 만들까? REQUIRES_NEW 는 어떻게 매번 새로운 트랜잭션을 만들까? 이 부분에 대해 알아볼 때 핵심적인 기능을 하는 클래스는 AbstractPlatformTransactionManager, JpaTransactionManager, TransactionSynchronizationManager 가 있다. 이 클래스들이 기존 트랜잭션이 있는지 확인한다. 없으면 새로운 트랜잭션 설정을 해주고, 기..
들어가면서 이번 글에서는 @Transactional 이 커밋되는 과정을 물리 트랜잭션, 논리 트랜잭션 2 경우에 대해 디버깅을 통해 공부한 과정을 정리할 예정이다. 스프링 트랜잭션에는 물리 트랜잭션과 논리 트랜잭션이란 개념이 있다. 물리 트랜잭션은 데이터베이스 커넥션을 통해 우리의 쿼리가 실제 커넥션을 통해 커밋/롤백 하는 역할을 한다. 논리 트랜잭션은 A라는 트랜잭션에 B 라는 트랜잭션이 참가하는 경우. 즉, 하나의 트랜잭션 내부에 다른 트랜잭션이 추가로 사용하는 경우 이 트랜잭션들을 논리 트랜잭션 이라고 한다. 트랜잭션이 하나라면 물리, 논리 트랜잭션을 구분하지 않는다. 트랜잭션의 COMMIT 동작 흐름 @TransactIonal 을 활용한 트랜잭션은 AbstractPlatformTransaction..
들어가면서, 우테코에서 프로젝트를 진행하면서 엔티티 상속 구조를 JOINED 전략을 사용한 적이 있었는데, 이 과정에서 경험한 상속 구조 사용 시 주의점에 대해 간략하게 정리할 예정이다. 상속 구조를 적용한 상황 우리 서비스는 2종류의 회원이 있다. 전화번호를 통해 가입한 임시회원 실제 우리 서비스에 접속해 회원가입을 한 정식 회원 그리고 임시회원인 상태에서도 여러 쿠폰을 발급 받을 수 있다. 결론 결론부터 빠르게 정리하자면 abstract 클래스의 dtype 을 변경할 일이 있을 때는 사용하기 부적절한 것 같다. 위에 작성한 dtype 변경 상황을 예로 들자면, 임시회원 상태에서 서비스에 접속해 회원가입 하면 해당 고객은 정식 회원 타입으로 변경해야 한다. 이 과정에서 customer 테이블의 dtyp..
들어가면서, 프로젝트 중 spring data jpa 의 deleteAll() 을 사용할 때 매우 많은 쿼리가 발생했는데, 그 이유와 해결방안에 대해서 작성할 예정입니다. 아래 사진과 같이 Coupon, CouponDesign 이 연관관계가 설정되어 있고, cascade.REMOVE 옵션도 설정되어 있는 상태에서 여러개의 Coupon 을 지우는 상황이다. Coupon @Entity public class Coupon extends BaseDate { @Id @GeneratedValue(strategy = IDENTITY) private Long id; private Boolean deleted = Boolean.FALSE; @ManyToOne(fetch = LAZY) @JoinColumn(name = "..