본문 바로가기

Programming

(110)
[Spring] Retry 재시도 로직 구현하기 With Kotlin 서버를 운영하다보면 일시적인 오류가 종종 발생한다. 특히나 어플리케이션 간의 통신에서 이러한 일시적인 오류가 빈번하게 생기는 편이다. 이러한 오류는 재시도를 통해 문제가 해결되는 케이스가 대부분이다. 이를 위해 스프링에서는 `@Retryable` 이라는 어노테이션을 제공해서 해당 메소드 위에 어노테이션만 붙여주면 간단하게 재시도 할 수 있는 로직을 구현할 수 있다. 하지만 AOP 특성 상 어노테이션이 동작하기 위해서는 외부에서 해당 메소드를 호출해야한다. 고작 한줄만 재시도 로직이 필요한 상황인데, 그 한줄을 다른 클래스로 빼야되는 귀찮은 상황이 발생할 수 있다. 여기저기 Retryable 어노테이션이 붙어있는 것과 위에서 언급한 AOP의 단점을 보완하기 위해 특정 비즈니스 로직을 재시도할 수 있는 Re..
JPA 변경감지(Dirty Checking)과 OSIV JPA를 사용할 때 변경 감지를 주의해야한다. 아무런 생각없이 중간 데이터 전달 경로로 엔티티의 필드를 건드린다면, 실제로 DB에도 변경이 적용되기 때문이다. 또한 주의해야할 점은 OSIV를 활성화 시켰을 경우이다. 다음 예제를 살펴보자. fun test() { val product1 = productItemRepository.findById(1L).orElse(null) product1.amount = product1.amount + 1 // 엔티티 값 변경 // osiv가 활성화되어있다면 여기서 product1은 영속성컨텍스트에 계속 살아있게된다. (영속 상태) // osiv가 반대로 비활성화 되어있다면 여기서 product1은 영속성컨텍스트에 남아있지 않는다. (준영속 detach 상태) dirty..
JPA 영속성 컨텍스트의 1차캐시 & 쓰기지연은 정말 동작하는가? JPA는 엔티티를 영속성 컨텍스트에서 관리한다. 영속성 컨텍스트에 대한 장점을 다시 한번 살펴보면 다음과 같다. 1. 1차 캐시 2. 동일성 보장 3. 트랜잭션을 지원하는 쓰기 지연 4. 변경 감지 이러한 영속성 컨텍스트의 장점은 많이들 접해보고 들어봤을 것이다. 이 글에서는 1차캐시와 쓰기지연에 대해서 좀 더 자세히 알아보도록 한다. 1차 캐시 1차 캐시가 되는 것은 오직 식별자로 쿼리할 때만이 가능하다. 식별자가 무엇인가? 바로 @Id 어노테이션을 붙여둔 Key이다. 다음 예제를 살펴보자. Person(id = 1, name = "A") 위와 같은 Entity가 DB에 저장되어 있다고 가정해보자. 여기서 다음과 같이 쿼리를 하면 어떤 일이 발생할까? val p1 = repository.findByNa..
JVM Memory와 Garbage Collection JVM Memory에 대해 알아보기 전에 JVM에 대한 구조와 개념을 살펴보자 프로그램이 실행되기 위해서는 Windows나 Linux같은 운영체제가 제어하고 있는 시스템 일부인 메모리(RAM)를 제어할 수 있어야 하는데, Java 이전에 C같은 대부분의 언어로 만들어진 프로그램은 이러한 이유 때문에 OS에 종속되어 실행되게 되었다. Java로 만들어진 프로그램은 JVM이라는 프로그램만 있으면 실행이 가능한데, JVM이 OS에게서 메모리 사용 권한을 할당받고 JVM이 Java 프로그램을 호출하여 실행한다. 이렇게 JVM위에서 동작할 수 있는건 JVM이 Java Byte Code를 OS에 맞게 해석해주는 역할을 해주기 때문이다. 하지만 JVM의 해석을 거치기 때문에 C언어 같은 네이티브 언어에비해 속도가 느..
< json parsing error 외부 업체와 통신 작업을 하고 있는데, 우리쪽 응답받는 부분에서 계속해서 < json parsing error ~ 에러가 계속해서 발생하였다. 뭔데 < 이걸 json으로 파싱하려 하는걸까?? 생각을 해보니 저 형태는 무언가 json형태가 아닌 html형식으로 response를 주는 것이 아닌가라는 추측을 하였다. 우리는 통신 라이브러리를 retrofit을 사용하고 있었다. retrofit의 converter 설정을 json converter를 사용하고 있었기 때문에 응답을 json으로 파싱하려한다. 실제 응답 결과를 보기 위해 curl을 날려본 결과 html로 응답을 오는 것을 확인하였고 json형태로 응답형식을 바꿔달라고 요청해서 해결하였다. 따라서 저러한 에러가 난다면, 응답의 형태가 json형태가 ..
[Spring] IntelliJ에서 종종 Build가 깨지는 오류 가끔가다 이유없이 IntelliJ에서 Build가 깨지는 오류가 있다. (→ 직접 gradle로 build하면 잘되는 경우) 어디간에서 꼬인 것 같은데, 이유는 잘 모르겠고 다음을 순서대로 수행해보며 해결해본다. Gradle Refresh 첫번째 방법으로 라이브러리가 꼬인 경우가 많으니 Gradle Refresh를 해준다. (IntelliJ 오른쪽 Gradle Tab -> refresh모양 버튼 클릭) Project Structure → Problem build가 깨지면 해당 페이지에 Problem이 표시된다. 라이브러리가 꼬인 케이스인데 여기서 수동으로 삭제해줄 수도 있다. (상위 File 탭 -> Project Structure -> Problem) File → Cache 삭제 IntelliJ Cac..
JPQL과 영속성 컨텍스트 스프링 웹 프로젝트를 작업할 때, 온전히 JPA만으로 작업하기에는 어려움이 따를 수 있다. 예를 들어, 테이블 중 특정 필드만이 필요한데, JPA로 모든 필드를 메모리에 올리기에는 비효율적인 문제등을 들 수 있을 것이다. JPQL과 JPA를 조합해서 쓸 때 몇가지 주의할 점과 동작하는 방식에 대해 알아본다. 먼저 JPQL의 개념을 간단하게 다시 한번 살펴보자. JPQL JPQL은 SQL과 비슷한 문법을 가진 객체 지향 쿼리이다. JPQL의 탄생 배경은 JPA에서 제공하는 메서드 호출만으로 섬세한 쿼리 작성이 어렵다는 문제로부터 비롯되었다. JPQL로 조회한 엔티티와 영속성 컨텍스트 JPQL로 엔티티를 조회하면 해당 엔티티는 영속성 컨텍스트에서 관리된다. 하지만, 엔티티가 아니라면 영속성 컨텍스트에서 관리..
Spring 순환참조(Circular Depencies) 해결하기 스프링에서 빈 순환참조가 일어날 때 회피하는 방법을 알아보자. Redesign 사실상 재설계하는 것이 가장 바람직한 방법이다. 하지만 실제 운용할 때에는 재설계할 수 없는 상황이 허다할 것이다. (레거시와 많이 엮여있거나, 이미 테스트가 끝난 경우) Use @Lazy 가장 심플한 방법으로 주입하는 곳에 @Lazy 키워드를 붙이는 것으로 해결할 수 있다. 완전히 빈을 초기화하는 것 대신에 프록시가 대신 주입되는 방법이다. 실제로 해당 빈이 사용될 때 빈이 주입되는 방식이다. Use Setter/Field Injection 가장 많이 사용되는 순환참조 회피 방법으로 Constructor 주입 방법 대신 Setter, Field 주입 방법을 사용하는 것이다. Use @PostConstructor 빈 주입을 @..