본문 바로가기

728x90

Spring

(25)
[JPA] 양방향 매핑 관계 로딩 방법 별로 살펴보기 (N+1 문제는 도대체 언제?) 개인적으로 너무 헷갈리고, 진심인데 블로그 포스트마다 내용이 다른 것 같기도 하다. 그냥 직접 하면서 최대한 가능한 상황들을 정리해보려고 한다. 더 헷갈리게만 만드는 장황한 설명따윈 없이, 그냥 내가 정리하고 싶기도 해서 특정 CASE 에 대한 결과만 정리하니, 참고하실 분들은 결과만 참고하시면 좋을 것 같다. 기본적으로 다음과 같이 클래스들이 있다. 이하로 정리되는 내용은 의 제목으로 정리된다. @Entity @Getter @NoArgsConstructor @Table(name = "groups") public class Group { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "group", fetch..
[JPA] 연관 객체 불러오기.. Fetch Join 정말 괜찮을까? 결론부터 말하자면 약간 뻘짓한 글이다. 그래도 긍정적으로 본다면 고민을 해봤다는 의의는 있으니.. 초보자의 수준에서 한 번 고민을 공유한다고 생각하면 될 것 같다. (1) 개요 서비스단을 개발하다 고민하게 된 부분이 있어서, 정리해보면서 결론을 만들어 나가보기로 했다. 우선 개요는 다음과 같다. Group 객체가 있고, Group 활동 안에 게시물인 Post 객체가 있으며, Post 에는 댓글인 Comment 객체가 있는 다음과 같은 상황이다. 아래에는 표시되어 있지 않지만, Member 객체가 당연히 있으며, Member 와 Group 사이에는 현재 상태가 기록되고, [강퇴 / 휴면 / 활동] 의 세 가지 상태로 관리된다. 이와 같은 관계는 많이 발생하는 일반적인 상황으로, 모두 비식별 관계이다. 이 ..
[Spring Security] 아니 왜 Forbidden 만 계속 오지?? Spring Security 를 사용하여 인증 & 인가를 도입한 프로젝트를 개발중이였다. 다음과 같은 설정 정도로만 간단히 가져간 이후 개발을 진행하고 있었다. 너무 설명을 대충 써놓은거 같아 추가해놓자면.. JWT TOKEN 을 사용하는 방식으로 바꾸었고, AuthenticationProvider, UsernamePasswordAuthenticationFilter 을 제어하여 로그인을 Custom 화 하였고, UsernamePasswordAuthenticationFilter (AbstsractAuthenticationProcessingFilter) 앞에 JwtAuthorizationFilter (그냥 OncePerRequestFilter 상속) 를 만들어줘서, Token 체킹을 해주도록 하였다. 그래서..
[Spring과 DB] 5-2 Spring 에서의 예외 추상화 * Spring 에서의 예외 추상화 스프링에서는 데이터 접근 예외 계층을 제공해준다. 이는 Error Code 처럼 종속적이지 않다. 위를 보면 개발을 하면서 많이 봤던 Exception 들의 모습들을 확인할 수 있다 (DataIntegrity, NonTransient, Grammer Exception 등등). 데이터 접근 계층에서의 최상단 예외는 DataAccessException.class 이며, 모두 RuntimeException 인 것을 확인할 수 있다. 모든 데이터 계층 예외는 두가지로 분류한다. 1. Transient - 동일한 SQL 을 다시 시도했을 때 성공할 가능성이 어느정도 있음. 일시적인 Exception 이라는 뜻. 2. NonTransient - 같은 시도를 하면, 똑같은 예외가 ..
[Spring과 DB] 5-1 Spring 에서의 예외처리 지원 우선 Java 기본기 중 체크 Exception 과 언체크 Exception (Runtime Exception) 의 차이에 대해서는 인지한 상태로 내용에 들어간다. 체크 예외는 코드가 지저분해지는 문제도 있지만, 가장 큰 문제는 유지보수 관점에서 처리하지도 못할 Exception 들을 처리해주는 ControllerAdvice 단까지 끌고 올라간다는게 Spring 에서의 체크 Exception 사용의 문제였다. 하지만 JDBC 기술을 사용한다면, SQLException 은 당연히 발생할 수 밖에 없다. 다음을 보자. 다음은 트랜젝션 동기화를 지원해주기 위해 DataSourceUtils 를 사용한 Repository 이다. public class MemberRepositoryV3 { private final..
[JPA] - 나머지 쿼리 1. 다형성 쿼리 > treat, item 등의 쿼리문 사용 가능 > ex) select i from Item i where treat(i as Book).author= 'kim'; // treat = 일종의 캐스팅 > 사용한 테이블 전략에 맞춤형으로 SQL이 나가게 됨. 2. 엔티티 직접 사용 > 엔티티 칼럼을 직접 사용하면, SQL에서는 당연히 해당 엔티티의 기본 키값을 사용 > 그냥 엔티티를 직접 파라미터로 전달해서 사용할 수 있다는 특징이 있음 가령, em.createQuery("select m from Member m where m = :member").setParameter("member", member) em.createQuery("select m from Member m where m.id..
[JPA] JPQL 쿼리 2 (FETCH JOIN의 등장) 1. 경로 표현식 * 경로 표현식 - 객체 그래프 내를 탐색하기 위한 필드 표현 방식 상태 필드 (State Field) > 단순 값 저장 필드 : m.username (m = alias 준다고 표현) 연관 필드 (AssoociationField) > 연관관계를 위한 필드 : 단일 값 연관 필드(경로) / 컬렉션 값 연관 필드 *상태 필드 상태 필드 >> 경로 탐색의 끝. 탐색 종료. 예를 들자. String query = "select m.username from JpqlMember m"; *단일 값 연관경로 username.~ 가 더이상 어디서 갈 수가 없음. 상태필드를 만나게 되면 탐색의 끝. String query = "select m team from JpqlMember m"; 연관관계 (One..
[JPA] JPQL 쿼리 결국 DB 조회를 위해선 쿼리를 짤 수밖에 없는데, JPQL, 네이티브 SQL, Query DSL 등 다양한 방법을 지원 JPA를 사용하면 결국 Entity 중심으로 개발할 수밖에 없음. > 검색을 할때도 테이블이 아닌 Entity 를 대상으로 검색을 해야해함. > 그렇다면 뭐,, DB 데이터를 다~ 들고 온다음에 메모리에서 다~ 실행해서 객체로 변환한 다음에 Entity 대상으로 검색을 할 수 있도록 해야하나? > 이거는 말이 안됨. > App이 필요한 Data만 DB에서 불러오려면 결국 ! SQL을 찍어야 함. JPA + SQL 을 지원하는 JPQL 을 지원함. > JPQL은 일반 SQL처럼 DB 테이블 대상으로 하는게 아니고, 객체를 대상으로 한다. 니가 하던게 다 Entity 대상으로 쿼리 짠거임..
[JPA] - 값 타입 > 1) 엔티티 타입 - @Entity 로 정의하는 클래스 객체 - 데이터가 변해도 식별자로 지속 추적 가능 > PK 값으로 구분 가능 2) 값 타입 - 변경시 추적이 어려운, 단순한 값으로 사용되는 자바 기본 타입 / 객체 값타입 기본값 / 임베디드 타입 / 컬렉션 타입 으로 나뉨 >> 값타입은 항상 불변객체로 한다라고 그냥 생각해도 됨 (아래 나옴) 기본값 - 생명 주기가 엔티티에 의존된다. 기본값, 기본 타입 은(int, double) 은 공유가 안된다. int a= b int b= a a = 20; 출력해보면 a =20, b = 10 이 된다. 하지만 클래스 (래퍼 클래스처럼) Integer a= new Integer(10); Integer b = a; a.setValue(20); // 이런거 없..
[JPA] 프록시와 연관관계 - 2 4) 영속성 전이 :CASCADE (생각보다 많이 씀) CASCADE 란? 즉시 로딩 레이지 로딩과 아무 관계도 아니다! (헷갈릴 수는 있음) 특정 엔티티를 영속화 시킬 때 연관 엔티티도 함께 영속화 시키는 것을 말한다. 예시를 다음과 같이 보자. @Entity @Data public class Parent { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "parent") private List children = new ArrayList(); public void addChild(Child child) { children.add(child); child.setParent(this); } } @Entity ..