DEV/Spring Data JPA 16

데이터베이스 트랜잭션과 락 2

트랜잭션의 격리 수준 DIRTY READ NON-REPEATABLE READ PHANTOM READ 1. READ UNCOMMITTED O O O 2. READ COMMITTED O O 3. REPREATABLE READ O 4. SERIALIZABLE 1. READ UNCOMMITTED 커밋되지 않은 데이터를 읽을 수 있습니다. 여러개의 트랜잭선이 동시에 수행되고 있을 때, 다른 트랜잭션에서 수정하고 아직 커밋하지 않은 데이터를 조회할 수 있습니다. 이를 DIRTY READ라고 합니다. 트랜잭선 A에서 수정하고 커밋하지 않은 데이터가 트랜잭션 B에서 DIRTY READ된 뒤에 커밋되지 않고 롤백된다면 데이터 정합성에 문제가 발생할 수 있습니다. 2. READ COMMITTED 커밋된 데이터만..

DEV/Spring Data JPA 2024.03.19

데이터베이스 트랜잭션과 락 1

트랜잭션과 락 트랜잭션과 락이 비슷한 개념으로 헷갈릴 수 있지만 목적에서 분명한 차이가 있습니다. 트랜잭션은 데이터의 정합성을 보장해주는 기능이고 락은 동시성을 제어하기 위한 기능입니다. 트랜잭션은 작업의 완정성을 보장해줍니다. 논리적인 작업 셋을 모두 처리하거나 모두 처리되지 않도록 처리해줍니다. 락은 동시성을 제어하기 위한 기능입니다. 만약 하나의 회원 정보에 여러 커넥션이 동시에 접근했을 때 락이 없으면 데이터를 동시에 변경하게 됩니다. 락은 여러 커넥션이 동시에 동일한 자원을 요청할 때 한 시점에는 하나의 커넥션만 변경할 수 있도록 보장해주는 역할을 합니다. 더 나아가서, 트랜잭션의 격리 수준은 여러 트랜잭션 사이에서 작업 결과를 어떻게 공유하고 차단할 것인가를 결정하는 레벨입니다. 트랜잭션의 범..

DEV/Spring Data JPA 2024.03.18

데이터베이스 트랜잭션 기초

데이터베이스 종류에 따른 인터페이스 통합 애플리케이션에서 데이터베이스를 사용할 때, 커넥션 연결 → 쿼리 전달 → 응답 반환의 흐름을 사용한다. 그런데 데이터베이스마다 커넥션을 연결하는 방법이 다르다. 이를 통일하기 위해서 JDBC 표준 인터페이스가 만들어졌다 (DriverManager) 일반 커넥션과 커넥션 풀의 도입 데이터베이스 커넥션을 사용할 때 커넥션 풀을 사용한다 직접 커넥션을 연결할 수도 있고, 커넥션 풀을 사용할 수도 있다. 커넥션을 조회하는 방법을 추상화한게 DataSource이다 DriverMangerDataSource HikariDataSource 트랜잭션의 도입 DataSource에서 가져온 커넥션에 대해서 JDBC 코드를 반복해서 작성해야 한다 자동커밋과 수동 커밋에 대한 옵션을 직..

DEV/Spring Data JPA 2024.03.18

Open Session In View

정의 OSIV란 데이터베이스 커넥션 시작 시점부터 API 응답이 끝날 때까지 영속성 컨텍스트와 데이터베이스 커넥션을 유지하는 것을 말합니다. Service 계층을 벗어난 범위에서 지연 로딩이 가능하려면 영속성 컨텍스트가 살아있어야 하고 영속성 컨텍스트는 데이버베이스 커넥션이 유지되어야 가능합니다. OSIV를 사용하면 View Template과 API 컨트롤러에서 지연로딩이 가능해집니다. 설정 springboot에서 OSIV설정의 기본 값은 true 입니다. spring.jpa.open-in-view:true Open Session In View : 하이버네이트 Open EntityManager In View : JPA OSIV를 켤 때 ****주의사항 OSIV를 켜두면 너무 오랜 시간 데이터베이스 커넥션..

DEV/Spring Data JPA 2024.03.18

Entity의 Id를 직접 지정할 때 주의사항 (persist vs merge)

시스템이 매우 큰 경우 또는 어떤 이유로든 Entity의 @Id를 직접 지정해야하는 경우가 있습니다. 이럴 때에는 아래와 같이 Persistable의 isNew를 override 해주어야 합니다. isNew 판단 여부는 Audit의 기능을 사용했습니다. @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Member extends BaseEntity implements Persistable { @Id @Column(name = "member_id") private String id; @Override public boolean isNew() { return super.getCreatedDate() == null; ..

DEV/Spring Data JPA 2023.09.27

JpaRepository를 custom해서 사용하는 방법

본 포스팅에서 제공하는 방법은 Java의 정식 문법을 따르지 않고, spring-data-jpa에서 제공하는 방법을 다루고 있습니다. 본문에 앞서 주의 사항이 먼저 있습니다. 비즈니스의 핵심 로직을 다루는 리포지토리와 화면에 맞춘 정적 쿼리를 조회하는 리포지토리는 분리해야합니다. custom repository의 기능 사용해서 하나의 entity에 대해 하나의 repository만 사용하게 되면, 어떤 경우에 어떤 메서드를 사용해야하는지 파악하기 어렵게 됩니다. 그리고 비즈니스 핵심로직과 화면에 맞춘 쿼리는 변경주기가 다르다는 점도 고려해야합니다. 먼저 커스텀 메서드가 필요한 인터페이스를 생성합니다. 이를 구현한 클래스를 생성합니다. 이 때 클래스 이름의 postfix는 반드시 Impl이어야 합니다. p..

DEV/Spring Data JPA 2023.09.24

QueryHint를 적용하기 전에 고려해볼 사항

변경감지를 위해서는 원본과 현재의 값을 어쩔 수 없이 둘 다 가지고 있어야 합니다. 어떤 부분이 변경되었는지 파악할 수 있어야하니까요. 정말 조회에만 영향이 있는 쿼리라면 별도의 MemberReadOnlyRepository를 분리해서 읽기 전용 조회를 구성할 수도 있습니다. 하지만 쿼리 힌트보다는 1차 캐시를 우선 적용해서 DB로의 쿼리 자체를 줄이는 것을 먼저 적용하는게 우선입니다. redis와 같은 별도의 구성 없이 쿼리힌트만으로 최적화가 될 수 있는지는 성능 테스트를 진행해봐야 합니다. @Repository public interface MemberJpaRepository extends JpaRepository { @QueryHints(value = @QueryHint(name = "org.hibe..

DEV/Spring Data JPA 2023.09.24

@EntityGraph로 fetch join 쉽게 쓰기

@ManyToOne, @OneToOne을 사용할 때는 몇 가지 정해진 규칙이 있습니다. 1. 불필요한 JOIN과 조회가 연속적으로 일어나는 것을 막기 위해 fetchType.LAZY 사용한다. 2. fetchType.LAZY로 인한 N+1 문제를 해결하기 위해 fetch join을 사용한다 쿼리를 작성하다보면 간단한 fetch join을 매번 @Query를 사용해서 JPQL을 직접 작성하기 번거로울 때가 있습니다. 이럴 때는 fetch join을 간단하게 적용하게 도와주는 @EntityGraph를 사용할 수 있습니다. @Repository public interface MemberJpaRepository extends JpaRepository { @Override // @Query("select m fr..

DEV/Spring Data JPA 2023.09.24

Update 쿼리를 호출할 때 주의사항 2가지

일반적으로는 Entity에 대한 수정사항은 변경감지를 통해서 진행됩니다. 하지만 여러 Entity에 대해서 update를 한 번에 처리해야하는 경우도 있습니다. @Repository public interface MemberJpaRepository extends JpaRepository { int addTokens(@Param("name") String name, @Param("amount") Integer amount); } select 쿼리와 달리 update 쿼리는 2가지를 신경써야 합니다. 1. @Modifying annotation을 추가해주어야 합니다. 2. Update 쿼리는 DB에 직접 호출됩니다. @Modifying가 없으면 테스트 코드 작성과정에서 검증될 가능성이 높기 때문에 큰 문제가..

DEV/Spring Data JPA 2023.09.24

Page<Entity>를 API의 응답으로 리턴하는 방법

pagination을 사용해서 조회한 Entity 정보를 API의 응답으로 제공할 때, 의외로 잘 모르시는 부분이 있습니다. Entity를 API의 응답으로 그대로 노출하면 안되기 때문에 아래와 같이 변환하시는 경우가 있습니다. Page memberList = memberJpaRepository.findPageByName("name", PageRequest.of(0, 10)); List memberDto = memberList.getContent() .stream() .map(m -> new MemberReadResponse(m.getId(), m.getName())) .collect(Collectors.toList()); response = new MemberResponseDto(memberDto, m..

DEV/Spring Data JPA 2023.09.24