PageableExecutionUtils란?Spring Data 라이브러리(org.springframework.data.support)에서 제공하는 헬퍼 클래스로,Page 객체(페이징 결과)를 생성할 때 불필요한 Count 쿼리 실행을 생략(Skip)하여 성능을 최적화해 줍니다.왜 PageableExecutionUtils가 필요한가?Spring Data JPA의 기본 페이징은 항상 2개의 쿼리를 실행1) content 조회 2) select count(*) ...마지막 페이지라면?요청한 size보다 결과가 적다면?더 이상 페이지가 없다는 것이 이미 명확하다면?→ count 쿼리는 쓸데없는 비용❌ 잘못된 방식long count = query.fetchCount(); //무조건 count 쿼리 실행됨List..
패턴 1 — Surrogate Key 방식 (가장 일반적)equals / hashCode 아예 구현하지 않음객체 동일성 = JVM 참조 동일성HashSet에 넣어도 안전id가 바뀌어도 hashCode 불변Hibernate 프록시도 안전@Entityclass Member( var name: String) { @Id @GeneratedValue var id: Long? = null}영속성 컨텍스트(1차 캐시)JPA는 이미 객체 동일성 컨텍스트를 갖고 있다같은 ID → 같은 객체 인스턴스 하나만 사용val m1 = em.find(Member::class.java, 1L)val m2 = em.find(Member::class.java, 1L)m1 === m2 // true////////..
@Entitydata class Member( @Id @GeneratedValue val id: Long = 0, var name: String)equals()와 hashCode() 문제: data class는 생성자에 있는 모든 필드를 사용하여 equals와 hashCode를 자동으로 만듦id = null (or 0) 인 상태로 엔티티 생성HashSet 또는 HashMap key로 사용persist() → DB가 id 생성Hibernate가 id를 새 값으로 변경hashCode() 변경 → 컬렉션에서 못 찾음equals / hashCode는 변하지 않는 식별자를 사용해야 한다순환 참조 및 지연 로딩 실패: 만약 생성자에 연관 관계(@OneToMany 등)가 포함되면, hashCod..
Body에 선언 - 안전한 Kotlin Entity 패턴 id는 클래스 바디에서 var로 선언id가 null이면 "아직 DB에 저장되지 않은 비영속(Transient) 상태자동 생성이 아니면 서비스/팩토리에서 member.id = "값" 형태로 세팅JPA는 프록시 객체 생성을 위해 기본 생성자가 필요자동으로 기본 생성자를 만들어주는 라이브러리 "plugin.noarg", "org.jetbrains.kotlin.plugin.jpa"Body에 선언하면 직접 equals와 hashCode를 구현하기 용이JPA Entity의 동등성은 오직 PK(Primary Key)로만 판단해야 안전영속화 전(Transient) 객체끼리 비교할 때도 동등으로 보고 싶은 경우는 PK 비교 안됨@Entityclass Member(..
nested class기본값: 아무 키워드 없이 클래스 안에 선언외부 클래스의 프로퍼티나 메서드에 접근할 수 없음Java로 치면 static class 와 동일class Outer { private val message = "Hello" class Nested { fun print() { // println(message) // ❌ 외부 클래스 접근 불가 println("I'm a nested class") } }}// 사용val nested = Outer.Nested()nested.print()inner classinner 키워드를 사용해야 함외부 클래스의 프로퍼티나 메서드에 접근 가능Java의 non-static inne..
기본 개념기본적으로 스프링 빈은 싱글톤(@Singleton) 이라서 애플리케이션 시작 시 한 번 생성되고 컨테이너가 내려갈 때까지 유지됩니다.하지만 웹 애플리케이션에서는 요청마다 다른 값을 유지해야 하는 경우가 많습니다. (예: 로그인 사용자 정보, 요청 ID, 트랜잭션 관련 데이터 등)이럴 때 @RequestScope를 사용하면 요청 단위로 새로운 빈을 생성할 수 있습니다.사용 예시/test API를 두 번 호출하면 매번 새로운 requestId가 생성됩니다.왜냐하면 RequestInfo 빈이 요청마다 새로 만들어지기 때문이에요.@Component@RequestScopeclass RequestInfo { val requestId: String = UUID.randomUUID().toString()..
Redis ZSet(sorted set, 정렬된 집합)Set(집합) 과 Sorted(정렬) 의 특성을 결합한 구조각 원소(member)가 고유(unique) 하면서 동시에 score(숫자형 가중치) 를 가질 수 있고, 이 score를 기준으로 정렬된 상태로 저장특징중복 없음일반 Set처럼 값은 중복될 수 없음.단, 값은 유일하지만 score는 중복 가능.정렬 유지score를 기준으로 자동 정렬.동일한 score일 경우, 멤버 이름(사전순)으로 정렬.랜덤 접근 가능순위 기반으로 접근 가능 (ex: 1등부터 10등까지).score 기반으로 접근 가능 (ex: score가 50 ~ 100인 값들).시간 복잡도내부적으로 Skip List + Hash Table 구조 사용.삽입/삭제/탐색: O(log N)순위 기..
CORS (Cross-Origin Resource Sharing)브라우저가 다른 출처(Origin)의 서버에 요청을 보낼 수 있는지 판단하는 보안 규칙Origin(출처)이란?아래 3개가 모두 같아야 같은 Origin입니다.요소예시ProtocolhttpsHostsnailvoyager.tistory.comPort443CORS가 필요한 이유브라우저가 아무 사이트나:쿠키 포함 요청사용자 인증 요청을 보낼 수 있으면 ❌ CSRF, 정보 탈취 위험Simple Request (프리플라이트 없음)조건 (모두 만족해야 함)메서드: GET, HEAD, POST헤더 제한적Content-Type:application/x-www-form-urlencodedmultipart/form-datatext/plainPreflight R..
What?jdk 이미지를 openjdk:11-jdk-slim 변경한 후에 엑셀 다운로드 기능이 불가java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11FontManagerWhy?Apache POI는 sun.awt.X11FontManager을 로드해서 사용하는데openjdk:11-jdk-slim 이미지는 X11 관련 폰트 및 AWT 그래픽 라이브러리 의존성이 빠져 있어서 클래스 로딩이 실패How?일반적인 패키지가 포함된 openjdk:11-jdk 이미지로 변경
Jackson의 @JsonAnySetter는 JSON 역직렬화(deserialization) 과정에서 Java 객체에 미리 정의되지 않은 (알 수 없는) 프로퍼티들을 처리하기 위해 사용되는 어노테이션주로 동적인 JSON 데이터를 다룰 때 유용하게 활용@JsonAnySetter로 알 수 없는 데이터를 받아 Map에 저장하고, @JsonAnyGetter를 사용해 직렬화 시 Map의 데이터를 다시 JSON 필드로 풀어주는 예시 { "name": "홍길동", "itemList": [ { "id": 1, "name": "itemA", "productNo": "A1"}, { "id": 2, "name": "itemB", "imageUrl": "imagB" } ]}import com.fasterxml..