본문 바로가기

kotlin

동시성 문제와 해결 방법들 - 2편 (분산락 with. Database Lock, Redis) 지난 포스팅에서 동시성 문제 해결 방법으로 Synchronized에 대해서 알아보았다. Synchronized를 활용한 동시성 해결은 분산 환경에서는 활용될 수 없다. 이번 포스팅에서는 데이터 베이스 Lock, 레디스를 활용한 분산락을 통해 동시성을 해결하는 방법에 대해서 알아보고자 한다. ✔️ Pessimistic Lock 활용 - Database Level 데이터 베이스에서 지원하는 Pessimistic Lock(비관적 락)을 활용하여 실제 데이터 베이스에 Exclusive Lock을 걸어서 데이터 정합성을 보장할 수 있다. 🔗 Exclusive Lock 배타적 잠금, 쓰기 잠금이라고 불린다. 한 트랜잭션에서 데이터를 변경하거나 쓰고자 할 때, 해당 트랜잭션이 완료될 때까지 레코드(row), 테이블(.. 더보기
동시성 문제와 해결 방법들 - 1편 (Synchronized) ✔️ 문제 코드 @Entity class PostLike( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0L, @Column(nullable = false) val postId: Long, likeCount: Long, ) { @Column(nullable = false) var likeCount: Long = likeCount private set fun increase() { this.likeCount += DEFAULT_INCREASED_LIKE_COUNT } } 테스트를 위한 도메인 구성으로 id 값과 postId 값 두 개를 생성했고, 편의성을 위해 postLikeId 값을 활용하여 접근해 좋아요 수 증가 및 조회.. 더보기
kotlin + Jpa Lazy Loading 트러블 슈팅 상황 1 Kotlin과 JPA를 사용하면서, 다음과 같은 plugins를 적용하고 LazyLoading을 사용하였으나, 적용되지 않는 문제가 발생하였다. kotlin("plugin.spring") version "1.8.21" kotlin("plugin.jpa") version "1.8.21" 🔎 plugin.spring: 다음과 같은 어노테이션이 붙은 코틀린 클래스에 대해 자동으로 붙는 final 키워드를 open 해주는 allOpen을 지원한다. Spring boot 2.x 버전부터 CGLIB Proxy 방식으로 Bean을 관리하고 있어, Target Class를 상속받아 프록시를 생성하기 때문에 open으로 열기 위해 사용한다. @Component, @Async, @Transactional, @Ca.. 더보기
Kotlin에서 Rest Docs 문서화 코드 개선하기 기존에는 테스트 결과를 문서화 하기 위해, Rest Docs에서 제공하는 FieldDescriptor를 다음과 같이 생성하였다. 그러다 보니 Field가 많으면 엄청난 양의 코드를 작성해야 하고 이 부분의 가독성이 떨어져 개선하고자 한다. ❌ 문제의 코드 restDocMockMvc.post("/test") { jsonContent(request) }.andExpect { status { isOk() } }.andDo { handle( MockMvcRestDocumentation.document( "{class-name}/test-success", requestFields( fieldWithPath("name").description("이름").attributes(field(EXAMPLE, request... 더보기
Kotlin + Spring DTO에서 NotNull 변수의 null Validation 📒 상황 data class FacilityReq( @NotNull val category: Category, @NotBlank val name: String ) ◼ 시설 등록 요청 DTO를 위와 같이 작성하고 name 값을 넣지 않고 요청을 보내면 에러가 발생한다. 💥 기대했던 에러는 name은 null이 될 수 없다는 에러였는데, 에러 API 응답으로 설정한 값과 다른 값이 응답으로 왔다. 📒 원인 name을 NotNull 타입인 String으로 설정해서 null을 허용하지 않는 타입으로 정의했다. 이로 인해, name이 null로 채워지게 된다면 @field:NotBlank validation 로직을 타기 전에 변수에 값을 할당하는 과정에서 예외가 발생하게 되어 다음과 같은 에러가 발생한다. 💥 H.. 더보기
[Kotlin] 범위 지정 함수 ✔ 범위 지정 함수 범위 지정 함수는 특정 객체에 대한 작업을 블록 내에서 실행할 수 있도록 하는 함수이다. 블록은 특정 객체에 대한 작업의 범위를 나타낸다. 특정 객체에 대한 작업을 블록에 작성하면 가독성이 증가하고 유지 보수가 쉬워진다. 수신 객체 지정 람다(함수)라고도 하며, 블록 내에서는 수신 객체를 명시하지 않거나, it을 호출하는 것만으로 수신 객체가 호출된다. Kotlin에서는 apply, run, let, also, with 5가지를 지원한다. ❗❗ apply ◼ apply는 수신 객체 내부 프로퍼티를 변경한 다음, 수신 객체 자체를 반환하기 위해 사용되는 함수이다. ◼ 객체 생성 시, 다양한 프로퍼티를 설정해야 하는 경우 사용한다. ◼ apply에서는 수신 객체로 apply의 수신 객체(.. 더보기
[Kotlin] 기본 문법 (4) * 기본 문법 - Data Class Data를 전달하는 목적으로 사용된다. Dto와 비슷한 역할을 한다. data class Person(val name: String, val age: Int,) 다양한 함수를 자동으로 생성한다. val person1 = Person(name = "test", age = 10) val person2 = Person(name = "test", age = 10) // 1. equals() println(person1 == person2) // true // 2. hashCode() println(person1.hashCode() == person2.hashCode()) // true val hashSet = hashSetOf(person1) println(hashSet.c.. 더보기
[Kotlin] 기본 문법 (2) * 기본 문법 - 예외 Kotlin의 모든 Exception Class는 최상위 Class인 Throwable을 상속한다. Error: 시스템에 비정상적인 상황이 발생할 경우, 예측이 어렵고 기본적으로 복구가 불가능하다. (OutOfMemoryError...) Checked Exception: 시스템에서 포착이 가능하여 try-catch로 복구가 가능, 예외 처리를 강제한다. (IOException, FileNotFoundException...) Unchecked Exception: 런타임 시에 발생하는 예외로 예외 처리를 강제하지 않는다. (NullPointerException...) Kotlin은 Java에 비해 Checked Exception 처리를 강제하지 않는다. fun main() { Thre.. 더보기