개요 JPA는 내부에 하나의 EntityManagerFactory가 존재하고, EntityManagerFactory가 여러개의 EntityManager들을 생성할 수 있으며, 이렇게 생성된 EntityManager는 영속성 컨텍스트를 생성해 엔티티의 영속성을 관리한다. EntityManager는 트랜잭션 범위 내에서 작동하는 것이 일반적이기 때문에 트랜잭션을 시작할 때 마다 새로운 EntityManger 인스턴스가 필요하며, 이는 트랜잭션 종료 시 폐기된다.스프링 컨테이너에 등록된 트랜잭션 매니저는 데이터베이스 커넥션을 획득하고, 반납하는 역할을 한다. 스프링에는 데이터베이스 커넥션 풀이라는 것이 존재하는데, 스프링은 빈으로 등록된 Datasource 객체를 통해 커넥션 풀을 관리한다. 이 커넥션 풀에 ..
개요 흔히 Spring Data JPA를 사용하기 위해서 JpaRepository 인터페이스를 사용할 때 아래와 같이 사용하고는 한다. public interface MemberRepository extends JpaRepository { } 예전에 Spring Data JPA에 관해 공부할 떄 @Repository 어노테이션을 생략해도 된다는 말을 들었는데, 그 이유에 대해서 짧게 정리해보고자 한다. @Repository @Repository라는 어노테이션은 왜 사용하는 걸까? 스프링부트 프로젝트에서 많이 사용되는 @Controller, @Service와 @Repository를 살펴보면, @Component 어노테이션이 있는 것을 확인할 수 있다. 스프링은 스프링 Main클래스에 등록되어 있는 @Com..
개요 Spring Data JPA가 제공하는 JPARepository 인터페이스는 PagingAndSortingRepository와 CrudRepository, Repository 인터페이스를 차례로 상속받는데, 그 중에서 페이지네이션을 지원하기 위한 repository가 PagingAndSortingRepository이다. PagingAndSortingRepository를 보면 Pageable 타입을 인자로 받고, Page타입을 반환하는 findAll() 추상메소드가 존재하는 것을 볼 수 있다. 여기서 인자로 넘어오는 Pageable 인터페이스는 페이지 번호, 페이지 크기, 정렬순서와 같은 정보들을 갖고 있으며, PageRequest의 of()라는 정적 팩토리 메소드를 통해서 Pageable 인터..
N+1 Problem N+1 문제란, 연관관계가 설정된 엔티티를 조회할 때 연관된 엔티티의 개수(N)만큼 추가적인 쿼리가 발생하는 문제를 말한다. Member와 Order, Delivery엔티티가 있다고 하자. Order는 주문정보를 담은 엔티티로, Member(회원)와 다대일 연관관계를 가지며, 배송정보를 담은 엔티티인 Delivery와는 일대일 연관관계를 갖는다. @Entity@Table(name="orders")@Getter @Setter@NoArgsConstructor(access = AccessLevel.PROTECTED)public class Order { @Id @GeneratedValue @Column(name="order_id") private Long id; ..
스프링의 트랜잭션 스프링을 사용하면 @Transactional 어노테이션을 사용하여 선언적 트랜잭션 관리를 하게 된다. 이렇게 선언적 트랜잭션 관리 방식을 사용하게 되면 프록시 방식의 AOP가 동작한다. 그 전에 앞서 공부했던 스프링의 db 연동과정부터 차례로 살펴보면 다음과 같은 흐름을 가진다. 0. 트랜잭션을 시작하기 위해서는 db 커넥션이 필요하다.1. 스프링 컨테이너에 등록된 트랜잭션 매니저는 datasource라는 객체를 통해서 스프링이 관리하는 커넥션 풀에서 커넥션을 획득한다.2. 트랜잭션 매니저는 트랜잭션 컨텍스트를 통해 생성된 커넥션을 트랜잭션 동기화 매니저에 보관한다. 트랜잭션 컨텍스트는 트랜잭션 매니저와 트랜잭션 동기화 매니저 사이에서 트랜잭션의 작업을 관리한다.3. 트랜잭션 동기화 ..
구체적인 상황은 다음과 같다. Admin 페이지에서 POST api 요청이 올때마다 db에서 기존 데이터들을 모두 제거한 후에 request body로 들어온 데이터들을 저장해주는 로직을 기대하고 다음과 같은 코드를 작성하였다. featureRepository.deleteAll()sectionRepository.deleteAll()//req로 들어온 데이터 저장... 하지만 클라이언트 qa중 500 server error가 발생한다는 말을 듣고 찾아보니 다음과 같은 로그가 남겨져 있는 것을 볼 수 있었다. 엔티티에서 unique값으로 설정해놓은 필드가 중복된다는 뜻이었다. 그런데 삽입된 데이터는 중복이 아예 없는데, 이상하다고 생각하면서 코드를 다시 보던 중 JPA 쓰기 지연과 관련된 문제일 수 있겠..
1. 일대일 매핑에서 어느쪽을 연관관계의 주인으로 하는것이 맞는가? 반드시 다(N)쪽이 fk를 가져 연관관계의 주인이 되는 다대일 관계와 다르게, 일대일 매핑의 경우 어느쪽이 fk를 갖게 하여 주인으로 설정하든 기능적으로 문제가 없다. 어느쪽을 연관관계의 주인으로 설정하는 것이 좋을까?일대일 매핑에서도 주 테이블(자주 접근하는 테이블)과 대상 테이블이 존재하는데, 일반적으로 주 테이블에 외래키가 있는 것이 좋다고 느꼈다. 내가 진행했던 프로젝트 중에, feature별로 고유 이름을 가지게 하고, 사용자들이 그 고유 이름을 기준으로 즐겨찾기를 등록하여 feature가 변경되거나 삭제되더라도 고유 이름에 대한 즐겨찾기는 유지되게 하는 요구사항이 있었다. @Entity@Table(name = "featu..
애플리케이션 서비스를 개발할 때 데이터는 DB에 보관하고, DB와의 연결을 위해서 애플리케이션(클라이언트)은 애플리케이션 서버를 이용하여 DB와의 연결을 구축했다. 이 연결은 구축된 커넥션을 통해서 sql을 전달하면 db에서 결과를 응답받는 식으로 진행되었는데, 문제는 DB의 종류마다 이 커넥션의 방법이 달라서 DB를 변경하면 애플리케이션 서버의 DB관련 코드도 변경해주어야 했다는 것이다. 이러한 불편함을 해소하기 위해서 JDBC라는 자바 커넥션 표준이 등장하게 된다. JPA의 구현체인 hibernate도 내부적으로 이러한 JDBC를 사용하여 DB와 통신한다. JDBC (Java DB Connectivity) JDBC는 자바에서 데이터베이스에 접근하기 위한 API들을 제공하는 라이브러리로, 연결-SQL ..
개요 스프링을 사용할때 기본적으로 JPARespository를 이용하여 DB에 대한 쿼리 메소드 기능을 사용하게 된다. 하지만 기본적인 CRUD기능이 아니라 더 복잡한 쿼리문을 작성하기 위해서는 네이티브 쿼리를 작성하거나, jpql을 사용해야 했다. https://eckrin.tistory.com/37 [JPA] 객체지향 쿼리 언어(JPQL) 0. 소개 DB에 접근하기 위해서는 기본적으로 쿼리문이 실행되어야 한다. jpa를 이용하면 기본적인 SQL문이 자동으로 나가게 되긴 하지만, 직접 쿼리문을 작성하여 쿼리를 보내야 할 때를 위해 SQL을 eckrin.tistory.com 하지만 jpql을 작성할 경우, 쿼리문이 복잡해질수록 쿼리 스트링이 길어지게 되고, jpql 문자열 자체에 오타 혹은 문법적인 오류..
JPA 양방향 매핑 사용시 순환참조 문제가 발생할 수 있다. 상단 코드에서 Board와 Reply 엔티티는 일대다 양방향 매핑을 사용하고 있으며, Reply가 연관관계의 주인이 되어 fk를 가진다. 얼핏 보면 큰 문제가 없어보이지만, 다음과 같은 코드를 작성하면 문제가 발생할 수 있다. @GetMapping("/test/board/{id}") public Board getBoard(@PathVariable int id) { return boardRepository.findById(id).get(); } 위 코드는 @PathVariable로 넘겨받은 id값을 바탕으로 레포지토리에서 Board객체를 찾아서 반환하는 코드이다. 여기서 jackson이라는 라이브러리가 Board객체의 getter를 사용하여 엔티..
변경 감지와 병합 영속성 컨텍스트가 더 이상 관리하지 않는 엔티티, 즉 식별자(id)를 기준으로 영속상태가 되어 DB에 저장되었던 적이 있지만 현재는 아닌 객체를 준영속 상태라고 한다. JPA가 관리하고 있는, 영속성 상태 객체의 변경감지는 transaction이 commit될때 작동한다. 하지만 준영속 상태의 엔티티는 JPA가 관리하지 않아서 변경 감지가 일어나지 않는다. 그래서 단순히 java 객체의 상태를 업데이트 하는 것만으로는 갱신이 일어나지 않는다. 이러한 준영속 상태의 엔티티를 변경하기 위해서는 변경 감지(Dirty Checking) 기능을 사용하거나, 병합(merge)를 사용할 수도 있다. 변경 감지 @Transactionalpublic void updateItem(Item item..
개요 DB에 접근하여 데이터를 수정하려면 쿼리를 DB로 날려주어야 한다. JPA를 사용하면 기본적인 SQL문이 자동으로 나가게 되긴 하지만, 직접 쿼리문을 작성하여 쿼리를 보내야 할 때를 위해 SQL을 추상화하여 만든 객체지향 SQL이 JPQL이다. JPQL은 SQL을 추상화했기 때문에 DB의 종류에 의존적이지 않다는 특징이 있다. (DB에 맞게 변환하는것은 jpa과 hibernate의 몫) 기본 활용법 JPQL의 문법은 SQL과 유사하다. SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN등 SQL 문법을 모두 지원한다. 다만 테이블을 대상으로 쿼리를 작성하는 일반 SQL문과 다르게 JPQL은 jpa의 사용에 맞추어 엔티티 객체를 대상으로 쿼리를 작성할 수 있다. SELE..