2023-06-07-TIL
2023-06-07-TIL
Today I Learned
JPA의 @Lob
@Lob은 필드를 대용량 객체(LOB) 컬럼에 매핑하라는 표시다. Hibernate 사용자 가이드의 예시처럼 그냥 String은 VARCHAR로, @Lob String은 CLOB으로 매핑되고, byte[]에 붙이면 BLOB이 된다. 실제 DDL 타입은 방언에 따라 달라서 MySQL에서는 TEXT나 LONGTEXT 계열이 된다. 단지 긴 문자열이 필요할 뿐이라면 @Lob 대신 @Column(length = ...)이나 columnDefinition으로 길이를 지정하는 방법도 있다. LOB은 DB에 따라 별도 저장 영역에 보관되고 드라이버마다 처리 방식이 달라서, 꼭 필요한 경우에만 쓰는 편이 이식성에 유리하다.
- https://stackoverflow.com/questions/72154180/what-difference-does-it-make-to-put-an-annotation-lob-or-not
- https://www.baeldung.com/hibernate-lob
@Column(length) vs @Size
둘 다 문자열 길이를 적는 것처럼 보이지만 역할이 다르다.
@Column(length = 50): JPA 매핑 정보다. 스키마를 자동 생성할 때VARCHAR(50)으로 쓰일 뿐, 저장 전에 길이를 검사하지 않는다. 긴 값을 넣으면 DB가 거부하거나 잘라낸다.@Size(max = 50): Bean Validation 제약이다. 엔티티를 저장하기 전에(그리고 컨트롤러의@Valid에서) 검증해 예외를 던진다.
Hibernate 사용자 가이드에 따르면 문자열 최대 길이는 @Column(length=...)으로도, Hibernate Validator의 @Size로도 지정할 수 있다. 즉 Hibernate는 @Size를 DDL 생성에도 반영한다. 그래서 검증과 스키마 정보를 한 번에 표현하려면 @Size가 낫다는 의견이 링크한 글의 요지다.
- https://velog.io/@gillog/JPA-Column-Annotation
- https://www.objectdb.com/api/java/jpa/Column
- https://blog.yevgnenll.me/posts/jpa-column-vs-size-what-is-different
Redis Sentinel과 클라이언트
Sentinel 구성에서는 마스터가 바뀔 수 있으므로 클라이언트가 마스터 주소를 고정해 두면 안 된다. Redis 문서의 Sentinel 클라이언트 가이드는 절차를 이렇게 정한다. 먼저 Sentinel 목록 중 하나에 접속하고, SENTINEL get-master-addr-by-name <master-name>으로 현재 마스터 주소를 묻는다. 그 주소에 접속한 뒤 ROLE 명령으로 정말 마스터인지 확인하고, 아니면 잠시 기다렸다가 처음부터 다시 시도한다. Lettuce, Jedis 같은 클라이언트와 Spring Data Redis의 Sentinel 설정이 이 절차를 대신 수행한다.
- https://redis.io/docs/reference/sentinel-clients/
RabbitMQ의 Routing Key
RabbitMQ에서 생산자는 큐가 아니라 익스체인지로 메시지를 보내고, 익스체인지가 바인딩 규칙에 따라 큐로 라우팅한다. 메시지에 붙는 routing key와 큐를 바인딩할 때 지정한 binding key를 비교하는 방식이 익스체인지 종류마다 다르다.
- direct: routing key와 binding key가 정확히 같은 큐로 보낸다.
- topic:
order.*.created,order.#처럼 점으로 구분한 패턴으로 매칭한다(*는 단어 하나,#은 0개 이상의 단어). - fanout: routing key를 무시하고 바인딩된 모든 큐로 보낸다.
headers: routing key 대신 메시지 헤더 값으로 매칭한다.
- https://www.educba.com/rabbitmq-routing-key/
- https://www.cloudamqp.com/blog/part4-rabbitmq-for-beginners-exchanges-routing-keys-bindings.html
- https://devahea.github.io/2019/04/30/rabbitmq-exchange-%EB%9D%BC%EC%9A%B0%ED%8C%85-%ED%8C%A8%ED%84%B4/
- AMQP 0-9-1 Model Explained (RabbitMQ)
Fan-out
fan-out은 하나의 출력이 여러 입력으로 퍼져 나가는 구조를 가리키는 말이다. 디지털 회로에서는 한 게이트의 출력이 연결될 수 있는 입력의 수를 뜻하고, 메시징에서는 메시지 하나를 여러 소비자에게 복제해 전달하는 패턴을 뜻한다. RabbitMQ 문서도 fanout 익스체인지를 바인딩된 모든 큐로 메시지를 보내는 브로드캐스트 용도로 설명한다. 주문 완료 이벤트 하나를 알림, 정산, 통계 서비스가 각자 받는 구성이 대표적이다.
- https://trts1004.tistory.com/12109335
강의 사이트
Spring Data JPA 강의 추천 글과 Baeldung 강의, 그리고 MOOC 플랫폼(edX, FutureLearn, Udacity) 목록이다. Domain Modeling Made Functional 책 페이지도 함께 저장했다.
- https://medium.com/javarevisited/5-best-spring-data-jpa-courses-for-java-developers-45e6438be3c9
- https://www.baeldung.com/learn-spring-data-jpa-course?affcode=22136_bkwjs9xa#certification-class
- https://pragprog.com/titles/swdddf/domain-modeling-made-functional/
- https://www.mooc.org/
- https://www.edx.org/
- https://www.futurelearn.com/
- https://www.udacity.com/
저작인접권, 저작권, 실연권
같은 노래에도 권리가 여러 겹 있다. 작사, 작곡자는 저작권을, 가수와 연주자 같은 실연자와 음반제작자, 방송사업자는 저작인접권을 가진다. 실연권은 흔히 실연자가 가진 저작인접권을 가리키는 말이다. 문화체육관광부 설명에 따르면 저작인접권은 저작물을 창작하지는 않지만 해설자, 매개자, 전달자 역할을 하는 사람에게 주는 권리다.
함께 저장한 Headphonesty 글은 권리가 아니라 음원 품질의 기술 용어를 다룬다. 샘플 레이트는 1초에 소리를 몇 번 측정하는지, 비트 깊이는 측정값 하나를 몇 비트로 표현하는지, 비트레이트는 1초 분량의 오디오에 쓰이는 데이터 양이다. 같은 녹음이라도 이 값에 따라 음원 파일의 크기와 품질이 달라진다.
- https://www.headphonesty.com/2019/07/sample-rate-bit-depth-bit-rate/
- https://www.copyright.or.kr/education/educlass/learning/common-sense/view.do?brdctsno=13080&brdclasscode=&nationcode=&searchText=&servicecode=12&searchTarget=ALL&brdctsstatecode=#:~:text=%EC%9D%B4%EB%9F%AC%ED%95%9C%20%EC%84%B1%EC%A7%88%EA%B3%BC%20%EB%82%B4%EC%9A%A9%EC%9D%84,%EA%B3%BC%20%EC%9C%A0%EC%82%AC%ED%95%9C%20%EA%B6%8C%EB%A6%AC%EB%9D%BC%EB%8A%94%20%EB%A7%90%EC%9E%85%EB%8B%88%EB%8B%A4.
- https://www.mcst.go.kr/kor/s_policy/copyright/netizen/netizen01.jsp#:~:text=%EC%A0%80%EC%9E%91%EC%9D%B8%EC%A0%91%EA%B6%8C%EC%9D%B4%EB%9E%80%2C%20%EA%B8%80%EC%9E%90%20%EA%B7%B8%EB%8C%80%EB%A1%9C,%EA%B6%8C%EB%A6%AC%EB%A5%BC%20%EB%B6%80%EC%97%AC%ED%95%98%EA%B3%A0%20%EC%9E%88%EB%8B%A4.
- https://mixing.co.kr/8685
- https://m.blog.naver.com/huihi68/221320421585
- https://maily.so/kimlou/posts/19e8f6
- https://www.pianistkeunyoungsong.com/2022/06/blog-post.html
- https://brunch.co.kr/@shadowblast/152
- https://ground.buv.co.kr/community/view/1063
Optional.isPresent 사용 줄이기
if (opt.isPresent()) { opt.get() ... }는 null 검사를 모양만 바꾼 것이라 Optional의 장점을 살리지 못한다. Optional Javadoc에 있는 메서드로 대부분 대체할 수 있다.
- 값이 없으면 예외:
orElseThrow(() -> new NotFoundException(id)) - 기본값:
orElse(value), 기본값 계산이 비싸면orElseGet(supplier) - 값이 있을 때만 실행:
ifPresent(consumer), 없을 때 처리까지 하려면ifPresentOrElse - 변환과 필터:
map,flatMap,filter
orElse의 인자는 값이 있어도 항상 먼저 평가된다는 점이 흔한 실수다. 또 Optional은 반환 타입용으로 설계되었으므로 필드나 메서드 파라미터에 쓰는 것은 권장되지 않는다.
- https://stackoverflow.com/questions/43202596/how-to-avoid-using-optional-get-and-optional-ispresent
- https://www.geeksforgeeks.org/optional-ispresent-method-in-java-with-examples/
- https://dzone.com/articles/optional-ispresent-is-bad-for-you
- https://www.baeldung.com/java-optional
JPA에서 join과 fetch join
JPQL의 일반 join은 조건 필터링에 연관 엔티티를 쓰기 위한 것이고, SELECT 절에 적은 엔티티만 결과로 채운다. 연관 엔티티가 지연 로딩이면 나중에 접근할 때 쿼리가 따로 나가 N+1 문제가 생긴다. join fetch는 연관 엔티티를 같은 SQL로 함께 조회해 영속성 컨텍스트에 채워 넣으므로 이후 접근에 추가 쿼리가 없다. 주의할 점은 컬렉션(@OneToMany)을 fetch join하면 행이 늘어나 중복 엔티티가 생길 수 있고(Hibernate 6부터는 자동으로 중복 제거), 컬렉션 fetch join과 페이징을 함께 쓰면 Hibernate가 메모리에서 페이징한다는 경고를 낸다는 것이다. 즉시 로딩(EAGER)은 쿼리마다 제어할 수 없으므로, 기본은 지연 로딩으로 두고 필요한 쿼리에서 fetch join하는 것이 일반적인 권장이다.
- https://www.baeldung.com/jpa-join-types
- https://cobbybb.tistory.com/18
- https://velog.io/@alswn9938/Eager%EA%B3%BC-Lazy
- https://mighty96.github.io/til/fetch_fetchjoin/
- https://stackoverflow.com/questions/17431312/what-is-the-difference-between-join-and-join-fetch-when-using-jpa-and-hibernate
- https://jaime-note.tistory.com/54
이전 작업이 끝나지 않았을 때 @Scheduled 기다리게 하기: ShedLock
한 인스턴스 안에서 @Scheduled 작업은 기본 스케줄러 스레드가 하나라 이전 실행이 끝나야 다음 실행이 시작된다. 문제는 서버가 여러 대일 때다. 각 인스턴스가 같은 시각에 같은 작업을 실행하므로 중복 처리가 일어난다. ShedLock은 README 설명대로 예약 작업이 같은 시점에 최대 한 번만 실행되도록 보장하는 라이브러리로, DB나 Redis 같은 공유 저장소에 락을 기록한다. @SchedulerLock(name = "...", lockAtMostFor = "...")의 lockAtMostFor는 실행 노드가 죽어도 락이 영원히 남지 않게 하는 상한이다. README는 ShedLock이 분산 스케줄러가 아니라 락일 뿐이라고 분명히 한다. 작업 분배나 재시도가 필요하면 Quartz 클러스터 같은 스케줄러를 써야 한다.
- https://dictionary.cambridge.org/example/english/scheduled-time
- https://stackoverflow.com/questions/54036507/how-wait-scheduled-till-previous-task-is-not-finished
- https://www.baeldung.com/shedlock-spring
- lukas-krecan/ShedLock (GitHub)
댓글
아직 댓글이 없습니다