Kotlin으로 JPA @ElementCollection 사용하기

최근 실무에서 오랜만에 JPA의 @ElementCollection 기능을 사용하게되었다. 많이 까먹은데다 정리해둔 것도 없어 처음 쓸때도 여러 번 검색하며 고민했고, 이런저런 에러도 마주하게 되어 간단히 정리해보려 한다. @ElementCollection 이란? JPA의 @ElementCollection은 값 타입 collection을 매핑할 때 사용할 수 있는 기능이다. @Entity가 아닌 기본 타입이나 Embeddable 클래스로 정의된 컬렉션을 참조할 때 사용한다. db상으로는 별도의 테이블을 생성하게 된다. 간단한 예시로 유저의 ‘신청’이라는 엔티티가 있고, ‘희망하는 날짜’를 여러개 체크할 수 있다고 가정하면 아래와 같이 구성해볼 수 있다. ...

2023년 2월 26일 · 580 단어 · Mihyang Gu

message queue를 활용해보자

분산시스템에서 많이 사용되는 메시지 큐 (message queue)에 대해 공부해봤다. 실무에서 필요한 상황들이 앞으로 더 많이 생길 것 같아서 보편적으로 어떤 상황에서 메시지큐 도입을 고려하고, 여러 구현체들 중 어떤 기술을 써야할지 등을 정리했다. 개념 특정 메시지가 최소 한번은 전달될 수 있도록 보장(보관된 메시지가 꺼낼때까지 안전히 보관된다는 특성, durability)하는 비동기 통신을 지원하는 컴포넌트이다. 기본 아키텍처는 producer(발행자)가 메시지를 생성하여 queue에 저장하고, consumer/subscriber(소비자/구독자)가 queue로부터 메시지를 받아 동작을 수행하는 구조. queue는 여기서 메시지의 버퍼 역할을 한다. ...

2023년 2월 12일 · 910 단어 · Mihyang Gu

쏙쏙들어오는 함수형 코딩 책 리뷰 & 주요 개념들

쏙쏙들어오는 함수형 코딩 책 장장 564p.나 되는 ‘쏙쏙 들어오는 함수형 코딩(에릭 노먼드 저)‘책의 1회독을 끝냈다. 함께 스터디한 팀원들이 없었다면 정말 쉽지 않았을 여정. 그리고 이 책은 정말 친절하다. 함수형 코딩이라는 개념을 처음 접하는 사람들을 대상으로 쓰여진 책이고 중간중간 나오는 연습문제와 챕터 마지막의 결론, 다음 챕터에서의 반복 등으로 어렵지않게 학습할 수 있다. 우리 스터디에서는 연습문제를 스터디 시간에 같이 풀고 토론했는데 그 시간이 더 이해를 높이는데 도움이 되었던 것 같다. 책의 예제는 자바스크립트로 되어있지만, 저자는 이 책이 자바스크립트 책이 아니라고 재차 강조한다. 아마 다른 함수형 언어를 안다면 책을 잘 따라갈 수 있을 듯 하다. ...

2022년 10월 30일 · 1046 단어 · Mihyang Gu

데이터 중심 애플리케이션 설계 1장 정리

2021년 11월부터 마틴 클레프만의 ‘데이터 중심 어플리케이션 설계’ 라는 책을 스터디하고 있다. 굉장히 컴팩트하고 심도있게 다루는 책이라 소화가 덜된 부분이 많다. 스터디는 끝나가지만 복습 차원에서 특히 중요했던 장들을 다시 정리해보려고 한다. Preface 데이터베이스, 분산 시스템 분야 발전의 원동력들 엄청난 양의 데이터와 트래픽을 다루게 됨 → 새로운 도구를 만들어야 했음 기업은 애자일하고, 빠르게 시장을 간파해 대처해야함 자유 오픈소스 소프트웨어 CPU 클록 속도는 거의 증가 x, 멀티 코어 프로세서가 표준이며 네트워크는 빨라지고 있음 → 병렬 처리는 계속 늘고있다 AWS같은 IaaS 덕분에 소규모 팀에서도 여러 장비에 분산 시스템을 개발할 수 있음 서비스에 고가용성을 요구하게 됨 데이터중심 애플리케이션(data-intensive application) 데이터 양, 복잡성, 데이터가 변하는 속도 등 데이터가 주요 도전 과제인 어플리케이션. ...

2022년 1월 2일 · 1161 단어 · Mihyang Gu

Spring security - N회이상 로그인 실패 에러처리 삽질 기록

요즘 처음으로 실무에서 Spring security로 인증 관련 로직을 구현하고 있다. 기본 로그인, 회원가입, 권한설정 등은 튜토리얼이나 문서가 많아 다소 쉽게 해결했는데, 별거 아닌듯한 부가적인 요구사항을 덧붙이는게 오히려 더 적용이 어려웠다. 그 중 로그인을 하다가 비밀번호를 여러번 잘못 치면 ‘n회연속 입력 오류’ 같은 에러 처리를 하기까지의 삽질 과정과 나름의 해결방법을 정리해봤다. 먼저 Rest API로 개발하기 위해서 만들어둔 AuthenticationFailureHandler 인터페이스의 구현체를 이용하려고 했다. (디폴트 FailureHandler를 쓰지 않는 이유는 로그인 페이지로 redirect하는 로직이 있기 때문이다. spring security에서 로그인 페이지에서 form인증을 하는게 디폴트라, Rest api 구현을 위해서는 로그인 실패 시 handler에서 redirect 없이 + 401 http status를 리턴해야한다.) 이 FailureHandler에서 로그인 실패시마다 카운팅을 하고, 숫자가 n회를 초과하면 에러메시지를 띄우면 되겠다고 생각했다. 인증 후의 실패를 담당하는 클래스이니 ProviderManager보다 더 책임을 수행하기에 적합하다고 생각했다. 그래서 다음 코드와 같은 로직을 짜기 시작했다. ...

2021년 12월 19일 · 587 단어 · Mihyang Gu

Binary-to-text encoding(base64, 32, 16, 62, 58)

웹개발을 하다보면 base64 같은 인코딩 방식들을 접하게 된다. 최근까지도 그냥 바이너리를 인코딩 하는 표준이겠지 정도만 생각해보았는데, 알아보니 흥미롭다. 문자 인코딩이란 무엇이며 어떤 방식의 인코딩을 base-N으로 부르는지, 또 base64 외에도비슷한 base62, base32, base16 같은 다른 표준들이 서로 어떤 차이가 있는지 등을 살펴본다. 문자 인코딩(character encoding) 인코딩(encoding)이란 사람이 쓰는 문자, 그림 등의 데이터를 → 컴퓨터가 이용할 수 있는 신호(0, 1)로 만드는 것이다. 문자 인코딩은 문자 데이터를 컴퓨터가 이용할 수 있는 신호로 만드는 것 대표적인 문자 인코딩 방식들 아스키코드(ASCII) ...

2021년 12월 5일 · 603 단어 · Mihyang Gu

Generic - Invariance, Covariance, Contravariance

Spring batch를 쓰다보면 ItemWriter에 void write(List<? extends T> var1) 이런 메서드가 있어 왜 저런 제네릭 타입을 쓰는걸까 궁금했었는데 이제서야 찾아보게 되었다. contravariance 개념에 대한 글들을 봐도 뭔가 직관적이지 않아서 이해하는데에만 몇 시간이나 걸렸는데, 이해하고 나니 어찌보면 단순하다. 최대한 정리해봤다. Generic 용어 처음엔 일단 뭐라고 검색해야할지 명칭조차 까먹어서 다시 정리를 해봤다. 이펙티브 자바에 나오는 용어 기준이다. ? : wildcard. unknown type을 나타낸다 List<?>: unbounded wildcard type(비한정적 와일드카드 타입) List<? extends Integer>, List<? super Integer> : bounded wildcard type(한정적 와일드카드 타입) ? super Integer : Integer이거나 Integer의 supertype이란 뜻 ? extends Integer : Integer이거나 Integer의 subtype이란 뜻 E : formal type parameter(정규타입 매개변수) List<E> : generic type Invariance, Covariance, Contravariance type과 subtype간의 관계 각각 불공변, 공변성, 반공변성으로 번역할 수 있는데…차라리 영어가 더 쉽다 in- 은 not, co- 는 함께, contra- 는 반대의 covariant: A가 B의 subtype이면 f(A)도 f(B)의 subtype contravariant: A가 B의 subtype이면 f(B)가 f(A)의 subtype invariant: 위에꺼 둘다 안됨 Invariance 1 2 3 4 5 6 interface Animal { void eat() } class Panda extends Animal { void eat() } Panda는 Animal의 하위 타입이지만, List<Panda>는 List<Animal>의 하위타입이 아니다. ...

2021년 11월 7일 · 731 단어 · Mihyang Gu

Java interface vs abstract class - 언제 무엇을 쓸까

‘인터페이스와 추상클래스의 차이’는 흔한 질문같지만 표면적인 차이 이상으로 들어가다보니 꽤 다양한 생각들을 만날 수 있었다. Java8에서 인터페이스에 ‘디폴트 메서드’를 추가할 수 있게 되어서 둘의 차이점이 많지 않아졌다. 언제 무엇을 쓰는게 바람직한가를 좀더 자세히 살펴봤다. 특징 먼저 기본적인 특징들을 살펴보자. 인터페이스 상수(static final ~) 와 추상메서드를 포함할 수 있다 1 2 3 4 interface Barkable { public static final int BLABLA_CONSTANT = 1; public abstract void bark(); } Java8부터 디폴트 메서드 (안에 구현까지 작성 가능)를 포함할 수 있다 ...

2021년 10월 24일 · 867 단어 · Mihyang Gu

RealMysql 6장 실행계획 정리

실행계획과 여러 상황에서의 인덱스 사용에 대해 상세히 알아보자. 6.1. 개요 실행계획이란 옵티마이저가 쿼리를 최적으로 실행하기 위해 각 테이블 데이터가 어떤 분포로 저장돼있는지 통계 정보를 참조해서 기본 데이터를 비교해 최적의 실행계획을 수립한다 쿼리 실행 절차 SQL문장을 쪼개서 Mysql서버가 이해할 수 있는 수준으로 분리 (= SQL 파싱) SQL의 파스트리 확인하면서 어떤 테이블부터 읽고 어떤 인덱스를 이용해 읽을지 선택(=최적화 및 실행계획 수립 by optimizer) 2단계에서 선택된 순서,인덱스로 스토리지 엔진으로부터 데이터를 가져온다 옵티마이저 종류 mysql을 포함한 대부분 rdbms가 비용기반 옵티마이저(cost-based optimizer) 를 채택함. 쿼리 처리를 위한 여러가지 가능한 방법을 만들고, 각 단위 작업의 비용정보와 대상 테이블의 예측된 통계 정보를 이용해 실행계획별 비용을 산출. 지금은 거의 안쓰이는 규칙기반 최적화도 있음(옵티마이저 내장 우선순위에 따라 실행계획 수립. 테이블의 레코드 건수, 컬럼값 분포도 등 통계정보 사용 x) 통계정보 대략의 레코드 건수, 인덱스의 유니크한 값 개수 등. 레코드 건수가 적으면 통계정보가 상당히 부정확. analyze 명령으로 강제로 갱신해야할 때도 있다 analyze명령: 인덱스 키 값의 분포도(선택도)를 업데이트 함 통계정보 수집할땐 랜덤하게 인덱스 페이지 8개 또는 innodb_stats_sample_pages 파라미터 값만큼만 읽어서 수집. (다읽는게 아님ㅋㅋ) 6.2. 실행계획 분석 update, insert, delete는 실행계획을 확인할 방법이 없다. where절만 같은 select를 만들어서 확인 가능 실행계획에 표시되는 각 칼럼 id 칼럼 select문 당 각각 다른 id. select_type 칼럼 SIMPLE - 서브쿼리 등 없는 단순 select PRIMARY - union이나 서브쿼리가 포함된 select에서 제일 바깥쪽 쿼리 UNION DEPENDENT UNION UNION RESULT SUBQUERY - from절 이외에서 사용되는 서브쿼리 DEPENDENT SUBQUERY - 서브쿼리가 바깥쪽 select에서 정의된 칼럼을 사용하는 경우. 외부 쿼리 먼저 → 서브쿼리 실행. 속도가 느리다 DERIVED - 서브쿼리가 from절에 사용된 경우. UNCACHEABLE SUBQUERY UNCACHEABLE UNION table 칼럼 실행계획은 단위select쿼리 기준이 아닌, 테이블 기준으로 표시됨. < >로 꺽쇠 안에 있는 <derived>나 <union> 같은건 임시테이블을 의미. <derived2>는 id 2번인 실행계획으로부터 만들어진 파생 테이블. 같은 id라면 윗 라인이 드라이빙 테이블. 드라이빙 테이블을 먼저 읽어서 드리븐 테이블을 조인한다. type 칼럼 mysql서버가 각 테이블의 레코드를 어떤 방식으로 읽었는지 mysql manual에서는 ‘join type’이라고 소개되어있음 어떤 값이 올 수 있는가 const : unique index 스캔. PK 키나 유니크 키 칼럼을 이용하는 where절로 반드시 1건을 반환하는 쿼리 처리방식 (select * from emp where id = 1) 다중칼럼으로 된 키 → const를 못씀. pk의 일부만 조건일때는 ref로 표시됨 옵티마이저에 의해 최적화 시 상수화된 후 (쿼리의 결과 자체를 상수화함) 쿼리 실행기로 전달하므로 const란 이름이. eq_ref: join을 쓰는 쿼리일때. 처음 읽은 테이블의 컬럼 값이 그 다음 테이블의 PK나 unique 키와 동등 비교 (select * from de, e where e.e_pk = de.empno;) ref : join과 상관없이, 제약조건 없이 동등 조건으로 검색 (select * from e where d = ‘1’;) 결과가 꼭 1건이 아니어도 됨 (const, eq_ref, ref 세개는 where절이 동등비교연산자여야함. 성능상 문제x. 매우 빠름) fulltext ref_or_null unique_subquery: where절에 쓰이는 in (subquery) 형태의 쿼리를 위한 접근방식. 서브쿼리에서 유니크한 값만 반환할 때. index_subquery: 위와 동일, 중복된 값을 반환할 때. 그렇지만 중복된 값을 인덱스를 이용해 제거할 수 있을 때. range: 인덱스 레인지 스캔! 인덱스를 하나의 값이 아닌 범위로 검색할 때 (부등호, is null, between, in, like) (( 인덱스를 효율적으로 쓰는 대표적인 방식. const, ref, range를 묶어서 인덱스 레인지 스캔이라고 지칭함 )) index_merge: 2개 이상의 인덱스를 이용해 각각의 검색결과를 만들고 merge. 여러 인덱스를 읽고 병합하는 과정 때문에 range보다 비효율적. AND, OR일때 주로 쓰이는듯한데 연산이 복잡하게 연결되면 제대로 최적화 안된다고 함. index: 인덱스 풀스캔. (인덱스를 처음부터 끝까지 다 읽음) 비교하는 레코드 수는 풀테이블스캔과 같으나, 인덱스가 크기가 더 작아서 더 빠르게 처리되고, 인덱스가 정렬된 것의 장점을 이용할 수 있다. 조건 (range, const, ref 방식을 못쓰는 경우) && (데이터파일 안읽고 인덱스에 포함된 칼럼만으로 처리가능 || 인덱스를 이용한 정렬이나 그룹핑이 가능한 경우) ALL :인덱스 안쓰고 풀테이블 스캔. - 가장 비효율적 possible keys 칼럼 옵티마이저가 고려했던 인덱스 후보 목록. 후보.. key 칼럼 최종 선택된! 인덱스를 표시함. index_merge를 제외하고 반드시 테이블 하나 당 하나의 인덱스만 이용가능. key_len 칼럼 인덱스의 각 레코드에서 몇 바이트까지 사용했는지 알려줌. 다중칼럼 인덱스일때 유용하다. key_len을 보면 다중칼럼인덱스에서 몇개의 칼럼까지 사용했는지 알수 있다 ((다중칼럼 인덱스가 2개라 치면 2개 다 조건절에 있어야 인덱스를 타는 것이 아님)) utf8문자 하나가 차지하는 공간은 1~3바이트, 메모리공간 할당은 3바이트로 고정됨 ref 칼럼 rows 칼럼 실행계획의 효율성 판단을 위해, 대상 테이블에 얼마나 많은 레코드가 포함되어있는지를 통계정보를 참조해 보여줌 예측이라서 실제랑 일치하지 않는 경우가 많다. 옵티마이저는 이 값을 참고해서 풀 테이블 스캔이랑 얼마 차이가 나지 않는다면 인덱스가 있어도 풀테이블 스캔을 해버릴수도 있다 extra 칼럼 성능과 관련된 문장 표시 Using join buffer Using where with pushed condition … 6.3. Mysql의 주요 처리방식 6.3.1. 풀테이블 스캔 fulltable scan 조건 테이블의 레코드 건수가 너무 작아서 인덱스를 통해 읽기보다 풀테이블 스캔이 더 빠른경우 where, on절에 인덱스를 이용할 수 있는 조건이 없는 경우 레인지스캔을 사용할 수 있는 쿼리지만 조건이 일치하는 레코드건수가 너무 많은경우 디스크 읽기 방식 InnoDB: 특정 테이블의 연속된 페이지가 읽히면 Read ahead 작업이 시작됨(백그라운드 스레드) 요청이 오기 전에 미리 디스크에서 읽어 버퍼풀에 저장 처음에는 foreground thread가 페이지 읽기를 실행, 특정시점부터는 백그라운드 스레드가 넘겨받아서 한번에 4, 8, … 페이지 읽으면서 계속 수를 증가시키고, foreground스레드는 버퍼풀에 준비된 데이터를 가져다 사용. 6.3.2. ORDER BY 처리 (using filesort) order by를 처리하기 위한 두가지 방법 인덱스 이용 → insert, update, delete쿼리 실행 시 인덱스를 정렬해놓음. 그래서 read는 굉장히 빠르지만 나머지는 느림 filesort 이용 → 정렬할 레코드가 많지 않으면 filesort로 충분함 extra칼럼에 “Using filesort"가 표시된걸로 확인 filesort 정렬 어떻게 함? 정렬을 수행하기 위한 메모리 공간 할당받아서 작업 - ‘소트 버퍼’ 근데 정렬할 레코드들이 소트버퍼 할당공간보다 더 크면?? 레코드를 여러 조각으로 나눠서 처리. 임시저장을 위해 디스크 사용 버퍼 크기만큼만 소트버퍼에서 처리하고 정렬된 결과는 디스크에 임시저장. 그리고 다시 병합하면서 정렬을 수행함. (multi-merge) sort버퍼 사이즈: ~1MB. 소트버퍼는 세션메모리영역(여러 클라이언트가 공유 못하고 각각 사용)이므로 커넥션이 많을수록 소트 버퍼 메모리공간이 커짐 정렬 알고리즘 Single pass (usually) 소트버퍼에 정렬기준 칼럼 + select되는 칼럼 다 담아서 정렬 수행. 더 많은 공간 필요 Two pass (일부 상황만) 정렬 대상 칼럼과 PK만 소트 버퍼에 담아서 정렬 수행, 정렬된 순서대로 다시 PK로 테이블을 읽어서 select할 칼럼을 가져옴 blob, text칼럼이 select대상일때, 레코드 크기 > max_length_for_sort_data 일때만 사용 정렬의 처리방식 인덱스 이용한 정렬 ORDER BY에 명시된 칼럼이 드라이빙 테이블에 속하고, ORDER BY의 순서대로 생성된 인덱스가 있어야 함. + WHERE절에 드라이빙 테이블의 칼럼에 대한 조건과 ORDER BY는 같은 인덱스를 써야. 인덱스의 값이 정렬되어있기 때문에 그냥 인덱스의 순서대로 읽기만 하는 것임. 드라이빙 테이블만 정렬 join을 하게되면 결과 레코드 수가 늘어나므로, 조인 실행 전에 첫번째 테이블의 레코드를 먼저 정렬한 다음 조인 실행. 조건: 드라이빙 테이블의 칼럼만으로 ORDER BY 절 구성 where절 만족하는 레코드들 찾기 → sort buffer로 복사 및 정렬 실행 → softbuffer결과와 나머지 테이블 조인 임시 테이블을 이용한 정렬 조인 결과를 임시 테이블에 저장, 그 결과를 다시 정렬함 정렬할 레코드가 가장 많고 가장 느림. ORDER BY절 칼럼이 드리븐 테이블인 경우 이렇게 할수밖에 없음 extra칼럼에 “Using temporary; Using filesort” 가 표시 6.3.3. GROUP BY 처리 6.3.4. DISTINCT 처리 실수 주의 select하는 레코드를 유니크하게 select함. 칼럼을 유니크하게 조회하는게 아님 select distinct first_name, last_name from emp → (first+ last) 전체가 유니크한 레코드를 가져옴 distinct는 함수가 아니므로 ``select distinct first_name, last_name from emp` 이렇게 해도 first만 distinct 안됨 count(distinct s.salary) 와 같은 집합함수 안에 쓰인건 그 컬럼에 대한 유니크한 것들 가져오는 거 6.3.5. 임시 테이블(using temporary) 6.3.6. 테이블 조인(!) inner join은 어느테이블을 먼저 읽어도 결과가 달라지지 않음 - 옵티마이저가 조인 순서를 조절해서 최적화. ...

2021년 9월 12일 · 1752 단어 · Mihyang Gu

elasticsearch index 내부를 알아보자

refresh를 해야 검색이 되는 이유

2021년 8월 15일 · 434 단어 · Mihyang Gu