Server/Spring JPA 24

JPA - Update(수정) 시 save() 메서드를 호출하는 것이 좋을까?

JPA를 사용하면 트랜잭션 범위 안에서 Dirty Checking이 동작한다. 따라서 save() 메서드를 호출하지 않아도 값이 알아서 수정되고 반영된다. 그렇다면 save()를 호출하는 것이랑 어떤 차이가 있는 지 알아보자. 차이 먼저 @Transactional만을 사용한 예제를 보자. @Transactional public Notice update(Long noticeId, String content) { Notice notice = noticeRepository.findById(noticeId).get(); notice.setContent(content); } 다음은 repository.save() 메서드를 사용한 예제를 보자. public Notice update(Long noticeId, Str..

Server/Spring JPA 2022.09.15

Spring - JpaRepository가 아닌 Repository를 사용해야 하는 이유!

Spring Data JPA를 사용하면 일반적으로 Repository에서 다음의 인터페이스 중 하나를 상속하여 사용하게 된다. JpaRepository CrudRepository Repository 해당 인터페이스들은 어떤 부분이 다르며 Repository를 사용하는 것을 권장하는 이유가 무엇인지 알아보자. JpaRepository 아래의 그림은 Spring Data Jpa에서 제공하는 인터페이스 사이의 상속관계를 정리한 것이다. 그림에서 아래로 갈 수록 저수준 모듈이며 기능 구현이 많음을 알 수 있다. CrudRepository의 경우 메서드를 정의하지 않아도 간단한 CRUD 사용이 가능하다. public interface AccountRepository extends CrudRepository { }..

Server/Spring JPA 2022.07.18

Spring Boot - 커넥션 풀 상태 확인하기!

Spring Boot 2.0 이상에서는 DBCP(DataBase Connection Pool) 구현체를 default로 HikariCP를 사용하고 있다. 다음의 HikariCP의 프로퍼티를 수정해서 현재 커넥션풀의 상태를 확인할 수 있다. application.properties logging.level.com.zaxxer.hikari=TRACE logging.level.com.zaxxer.hikari.HikariConfig=DEBUG application.yml logging: level: com.zaxxer.hikari: TRACE com.zaxxer.hikari.HikariConfig: DEBUG 결과 아래와 같은 로그를 확인하는 것이 가능하다. 예제 앱에서는 데이터 소스를 4개 사용하고 있다. 하..

Server/Spring JPA 2022.06.11

QueryDSL - Select 성능 개선하는 방법들! (+ JPQL 관련 이슈)

해당 포스팅은 "[우아콘2020] 수십억건에서 QUERYDSL 사용하기" 라는 영상의 내용을 정리한 글입니다. 해당 영상은 아래 Reference에서 시청할 수 있습니다. - https://www.youtube.com/watch?v=zMAX7g6rO_Y exist 메소드 금지 SQL문 중 exists 문은 조건을 만족하는 레코드를 1개 찾으면 바로 결과를 반환하고 쿼리를 종료한다. 반면 count(1)의 경우 마지막 레코드까지 검사를 하게 되기 때문에 성능이 낭비된다. 이런 성능차이는 스캔 대상이 앞에 위치할수록 더 심하게 발생한다. 문제는 QueryDSL의 exists는 SQL문의 exists를 사용하지 않고 count()>0로 쿼리를 날린다. 이를 개선하기 위해서 Querydsl의 selectOne..

Server/Spring JPA 2022.05.29

Java - LazyConnectionDataSourceProxy란? (+Dynamic DataSource)

LazyConnectionDataSourceProxy Spring은 트랜잭션에 진입하면 즉시 미리 DataSource의 커넥션을 가져온다. 가령 ServiceLayer Method에 @Transactional이 걸려있다고 가정하자. 쿼리를 날리기 전에 여러가지 복잡한 작업이 있을 수 있다. 그런데 Spring에서는 @Transactional에 진입한 순간 바로 커넥션을 걸어버린다. 이런 방식은 여러 단점이 있다. Ehcache같은 캐시를 사용하는 경우 실제 DB에 접근하지 않지만 불필요한 커넥션을 점유 JPA의 영속성 컨텍스트에서 엔터티가 존재함에도 불필요한 커넥션을 점유 Dynamic DataSource 환경에서 DataSource도 정해지지 않았는데 트랜잭션에 진입하면서 에러 터짐 커넥션 점유시간이 ..

Server/Spring JPA 2022.05.21

JPA - find만 했는데 Update쿼리가 나가는 이유

JPA에서 단순하게 find로 엔터리를 조회만 했는데, SELECT문 이후 UPDATE문이 나가는 것을 확인했다. Repository는 너무 간결해서 의심할 것도 없었고 엔터티 문제라고 확신했다. 해당 엔터티는 아래와 같다. @Entity @Table(name = "setting", schema = "mail") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Setting { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Long officeId; @Column(name = "auto_complete_flag") @Conver..

Server/Spring JPA 2022.05.21

QueryDSL - 벌크(Bulk) 연산 시 주의할 점!

벌크(Bulk) 연산 주의사항 Querydsl에서 Bulk 연산을 할 때 주의사항이 있다. 예를 통해 살펴보자. 아래 메서드는 모든 member의 money를 0으로 초기화한다. public void bulkUpdate() { // init Money queryFactory .update(member) .set(member.money, 0) .execute(); } 문제는 이때 쿼리를 날려서 DB에 반영은 하지만, 영속성 컨텍스트에 반영하지 않는다. 문제 상황 기존에 아래와 같이 Member가 3개가 있다고 가정하자. - id: 1, money: 10000 - id: 2, money: 20000 - id: 3, money: 30000 해당 Member들이 영속성 컨텍스트에 들어 있을 때 Bulk 연산을 ..

Server/Spring JPA 2022.05.08

Querydsl - 동적 쿼리(Dynamic SQL) 사용하기 !

동적 쿼리란 ? 동적 쿼리란 상황에 따라 다른 문법의 SQL을 적용하는 것을 말한다. 예를 들면 DB에서 값을 조회할 때 조회 조건이 동적으로 바뀌어야 하는 경우가 많다. 이런 상황을 Querydsl을 사용하면 손쉽게 해결할 수 있다. name 값이 들어오면 WHERE name = ${name} age 값이 들어오면 WHERE age = ${age} name과 age가 모두 들어오면 WHERE name = ${name} AND age=${age} name과 age 모두 들어오지 않으면 WHERE 절을 사용하지 않는다. 이를 해결하기 위한 방법을 살펴보자. 1. BooleanBuilder 동적 쿼리를 해결하려고 BooleanBuilder를 사용하는 걸 자주 볼 수 있다. private List search..

Server/Spring JPA 2022.05.07

Spring - 샤딩 모듈 개발 이야기 (feat. AbstractRoutingDataSource)

동적 데이터 소스와 스키마 이름API를 개발할 때 Java Spring으로 프로젝트를 진행하고 싶었는데 어려움이 있었다.해당 문제를 해결하고 세미나에서 발표한 내용에 대해 정리한다.모든 아키텍처나 코드는 실제 서비스와 무관하며 설명을 위해 만든 부분임을 알린다.API를 Java Spring으로 할 수 없었던 이유는 서비스의 DB구조 때문이었다.구조를 보면 DB 서버를 여러 대로 샤딩(Sharding) 하고 있고, 스키마도 분산되어 있다.데이터를 저장할 때 유저가 속한 지역별로 데이터를 특정 DB서버의 특정 스키마에 저장해서 사용한다.board_01에서 01을 파티션이라고 칭한다.특정 유저의 정보가 어떤 DB 서버의 몇 번째 파티션(스키마) 에 저장되어 있는지는 Region DB에 저장되어 있고, DB를 ..

Server/Spring JPA 2022.05.05

JPA - 비관적 락, 낙관적 락 (+ 트랜잭션 격리 수준) 정리!

격리 수준 락(Lock)을 이해하기 전에 트랜잭션 격리 수준을 먼저 알아야한다. 트랜잭션 격리수준(isolation level)이란 동시에 여러 트랜잭션을 처리할 때, 트랜잭션이 얼마나 서로 고립되어 있는지를 의미한다. 즉, 해당 트랜잭션이 다른 트랜잭션에서 변경한 데이터를 볼 수 있는 기준을 결정하는 것이다. 격리수준은 크게 4가지로 나눌 수 있다. READ UNCOMMITTED 커밋되지 않은 데이터를 읽을 수 있다. Dirty Read, Dirty Write가 발생할 수 있다. READ COMMITTED 커밋된 데이터만 읽을 수 있다. 오라클 DBMS에서 표준으로 사용하고 있고 가장 많이 선택된다. Lost Update, Write Skew, Read Skew가 발생할 수 있다. REPETABLE R..

Server/Spring JPA 2022.04.17