전체 글 361

SQL - WHERE 절, ON 절 제대로 이해하기!

최근에 팀원 분이 LEFT OUTER JOIN의 ON 절에 일반 조건이 포함된 쿼리를 작성하신 것을 봤다. SELECT * FROM team t LEFT OUTER JOIN member m ON t.id = m.team_id AND m.team_id = 4; 해당 부분이 예상대로 동작하지 않을 것을 예상하고 리뷰를 드리면서, 생각보다 잘 모르시는 분이 많으실 것 같아 정리하게 되었다. 미리 말하지만 해당 SQL은 의도대로 동작하지 않는다. ON 절과 WHERE 절의 차이에 대해 알아보자. Sample Data 삽입 테스트를 위해 데이터를 삽입했다. Team을 5개 삽입 각 팀별 멤버를 2개 삽입 WHERE SELECT * FROM team t LEFT OUTER JOIN member m ON t.id =..

Database/SQL 2023.11.21

JPA - OSIV 제대로 이해하기!

OSIV(Open Session In View) OSIV(Open Session In View)는 영속성 컨텍스트를 뷰까지 개방하는 기능이다. 이를 사용하면 트랜잭션이 종료되어도 영속성 컨텍스트가 관리될 수 있다. 여기까지는 사실 다 아는 내용이고 OSIV의 동작 원리에 대해 알아보자. OpenInView Spring 환경에서 보통 아래의 property로 OSIV 설정에 접근한다. spring.jpa.open-in-view 아래는 JpaWebConfiguration 클래스의 애노테이션이다. open-in-view 속성에 따라 해당 Configuration이 등록된다는 것을 알 수 있다. 이를 통해 알 수 있는 놀라운 사실은 'Spring JPA도 웹과 연관이 있다.'는 것이다. JpaProperties..

Server/Spring JPA 2023.11.19

Spring에서의 Proxy, AOP 동작원리 이해하기!

지난번 Spring AOP를 적용하면서 생겼던 문제에 대해 소개했다. https://jaehoney.tistory.com/375 이번 포스팅에서는 실무보다는 기본 개념에 대해 집중적으로 알아보자. 해당 포스팅은 김영한님의 스프링 핵심 원리 - 고급편의 프록시 관련 내용을 정리한 것이며, 프록시와 AOP의 동작의 기본 개념이라고 보면 된다. 프록시 패턴 프록시 패턴에서는 프록시가 너무 많이 생기는 문제가 있다. 아래는 GOF 프록시 패턴의 예시이다. 예로 들면 Repository 1개마다 전부 프록시 클래스를 생성해야 한다. 프록시를 적용할 클래스가 100개라면 100개의 프록시를 적용하는 코드를 만들어야 한다. 즉, 단일 책임 원칙에 어긋나고 기능 변경 시 다수의 클래스에 변경이 전파된다. 이 문제를 해..

Server/Spring 2023.11.16

Hibernate @Where 애노테이션이 동작하지 않는 이유!

@Where 애노테이션이 동작하지 않는 이유실무에서 Learning 테이블 레코드를 일괄 수정 시 인덱스를 타지 않는 문제가 발생했다.이유는 @Where(clause = "del_flag = 'N'")을 했는데, QueryDsl을 사용한 조회에서는 해당 조건을 수행하지 않아서 인덱스를 탈 수 없었다.요즘 Hibernate 및 JPA에 대한 관심이 부쩍 늘어서 이 문제에 접근해보면 경험치를 얻을 수 있을 것 같아서 디버깅해봤다.문제 파악다른 코드에 대한 영향 없이 확인해야 하기 때문에 새로 프로젝트를 만들었다.아래의 JPA Entity를 만들었다.@Entity@Getter@NoArgsConstructor(access = AccessLevel.PROTECTED)@Where(clause = "name = 'v..

Server/Spring JPA 2023.11.05

Spring의 Servlet에 X-Forwarded-For 헤더가 왜 안들어올까?!

아래는 실무 중에 만난 이슈와 해결 과정에 대해 다룬다.정확한 원인과 해결 방법보다는 풀어나간 과정에 집중되어 있다.원인과 해결 방안이 궁금한 분은 가장 아래로 내리시면 될 것 같습니다!헤더에 X-Forwarded-For이 안들어오는 문제 발견아래는 공통 라이브러리의 코드의 일부 코드를 요약한 것이다.public class HeaderUtil { static public HeaderInfo initHeaderInfo(HttpServletRequest request){ return HeaderInfo.builder() .token(request.getHeader(HeaderInfo.JWT_HEADER)) .clientIp(request..

Server/Spring 2023.10.26

단위 테스트 대상 분리하기!

아래는 최범균님의 유튜브를 보고 느낀 점을 나름대로 정리한 것이다. https://www.youtube.com/watch?v=qZ1R0C_iiV4 테스트 불가능한 문제 아래의 코드가 테스트가 불가능한 문제가 있었다고 한다. ResultBuilder builder = ...; InputPeriod realPeriod = mapper.selectPeriod(param); // 1. DB에서 읽음 if (realPeriod == null) { // 2. 없으면 다른 값 읽음 InputPeriod expectedPeriod = mapper.selectExpectedPeriod(otherParam); builder.period(expectedPeriod).type(EXPECTED); } else if (realP..

Accept 헤더가 포함된 REST API에서 에러를 내려주는 방법!

이번 포스팅은 회사에서 메일 원문 다운로드 API를 개발하면서 생긴 이슈에 대해 공유한다. 이해하기 쉽도록 메일 원문 대신 첨부 파일로 재해석해서 작성했다. 요즘은 파일 스토리지로 외부 인프라를 많이 사용해서 직접 설계해야 되는 상황이 드물긴 하다. 파일 접근 게시판의 첨부파일 기능을 생각해보자. 메타 데이터에는 빨간 네모와 같이 파일명과 확장자, 파일 사이즈, 다운로드 경로 등이 저장될 것이다. 다운로드를 클릭하면 실제 파일 스토리지에 접근해서 파일을 Binary 형태로 가져올 것이다. 게시판을 노출하기 위해서 메타 데이터를 가져올 때 파일 정보까지 모두 가져오면 오버헤드가 발생할 것이다. 그래서 2개의 End-point로 분리했다. Accept REST API에서는 url에 자원에 대한 경로를 지정한..

Server/Spring 2023.10.20

자바에서 동시성을 다룰 때 주의할 점!

아래는 이펙티브 자바의 내용 중 동시성에 대한 부분을 정리한 것이다. Effective Java는 동시성을 사용할 때의 몇가지 주의사항과 가이드라인을 제시한다. 동기화된 메서드 설계 시 주의할 점 동기화된 메서드를 작성할 때 중요한 것은 재정의할 수 있는 메서드를 호출해선 안되고 클라이언트가 넘겨준 함수 객체도 사용하면 안된다는 것이다. public class ObservableSet extends ForwardingSet { public void addObserver(SetObserver observer) { synchronized (observers) { observers.add(observer); } } public boolean removeObserver(SetObserver observer) {..

Language/Java 2023.10.17

Java 검사(Checked) 예외와 비검사(Unchecked) 예외

아래는 이펙티브 자바의 내용 중 예외에 대한 부분의 일부이다. 이펙티브 자바도 그렇고, 예외도 그렇고 포스팅할 내용이 너무 너무 많아서 다 정리할 수 없어서 아쉽다..! 일반적으로 검사 예외와 비검사 예외를 CheckedException, UncheckedException이라고 명명하지만, 해당 포스팅에서는 Effective Java의 명칭대로 검사 예외와 비검사 예외라고 명칭한다. 검사 예외와 비검사 예외 Throwable 클래스를 상속하는 것은 Error와 Exception이 있다. Exception을 상속하면서 RuntimeException을 상속하지 않으면 검사 예외이고, RuntimeException을 상속하면 비검사 예외라고 부른다. 참고로 Error는 Throwable을 상속하고 OutOfM..

Language/Java 2023.10.12

Spring - Bean은 어디에 저장되나?

스프링 공식 문서를 읽다가 Spring Bean은 어떤 자료구조에 저장되어 있고 어떤 과정으로 찾아서 의존을 주입하는 지가 궁금해졌다. 해당 부분을 찾아가면서 알게된 결과에 대해 다룬다. 아래에서 말하는 Bean은 싱글톤 빈임을 가정한다. 들어가기 전에 Spring의 경우 템플릿 메서드 패턴과 전략 패턴을 충분히 활용해서 수 많은 인터페이스에 책임을 위임하고 있고 구현체도 아주 많다. 그러다보니 자세히 다루면 양이 너무 방대해지는 문제가 있어서 어디까지 다룰 것인가에 대한 고민이 있었다. 너무 Deep한 문제는 다루지 않고 내용을 다루기에 이해가 필요한 부분까지만 다룰 것이니 겁먹지 마시고 봐주시면 좋겠다! getBean() 아래를 보면 ApplicationContext의 refresh()가 수행되면 i..

Server/Spring 2023.10.09