목록분류 전체보기 (106)
훈훈훈
Introduction WebClient 를 사용하여 외부 API 를 Mock 기반 테스트를 할 때, response 값에 대한 stub 객체를 만드는 방법에 대하여 정리해보려고 한다. 전체 코드는 Github 에서 확인할 수 있다. Problems 일반적으로 Mockito 를 사용할 때 아래와 같은 방법으로 stub 객체를 만들 수 있다. ( Mockito 는 BDD 방식을 지원하기 때문에 when( ) 대신 좀 더 가독성이 좋은 given ( ) 을 사용하였다. ) given(webClientWrapper.get() .uri("http://localhost:8080/test") .retrieve() .bodyToMono(String.class) .block() ).willReturn("ok"); 하지..
Introduction 이번에는 Mybatis 와 JPA 를 동시에 적용한 환경에서 어떤 transactionManager 를 사용해야되는지 살펴보려고 한다. 해당 글은 스프링에서 트랜잭션을 담당하는 핵심 인터페이스인 PlatformTransactionManager 를 먼저 정리 후, Mybatis 그리고 JPA 에 대한 내용을 정리하는 순서로 작성하였다. PlatformTransactionManager 스프링 트랜잭션 추상화의 핵심 인터페이스이다. 모든 스프링 트랜잭션 기능과 코드는 이 인터페이스를 통해 트랜잭션 서비스를 이용할 수 있다. 아래는 해당 인터페이스에 정의 된 메서드 목록이다. getTransaction( ) 메서드는 트랜잭션 속성에 따라 새로 생성하거나 진행 중인 트랜잭션에 참여하거나, ..
Replication 이란 ? 데이터베이스의 부하를 분산시키는 방법 중 하나이다. Write 관련 작업들은 Master DB 에서 처리를 하고 Read 관련 작업들은 Slave DB 에서 처리를 통해 부하는 분산 시키는 전략이다. 대부분의 서비스들은 Read 관련 작업들이 많기 때문에 Slave DB 를 여러 대 두어 분산시킬 수 있다. 단, 주의할 점은 Replication 은 짧은 시차가 존재한다는 점이다. Master 와 Slave 간의 Sync 를 맞추는 간격 사이에서 데이터의 정합성이 깨질 수 있다. 따라서 Master 에서도 읽기 작업이 필요한 순간들이 있다. 코드구현 Java 는 JDBC 커넥션 객체의 Connection.setReadOnly(true | false) 메소드를 통해 Repli..
아래 내용은 스프링 공식문서 스터디에서 정리했던 자료 입니다. Task Execution and Scheduling 1. Executor (1) Executor 란? Java 5에 도입되었으며, 단순히 void execute(Runnable command); 메서드만 정의된 객체이다. command 를 실행할 때 마다 새로운 스레드에 동작 command 는 Runnable 인터페이스 객체이다. Executor 가 실행될 때는 쓰레드를 명시하지 않는다고 한다. 그 역할은 Runnable 인터페이스가 대신한다. executor.execute(new RunnableTask()); 이런 식으로 command 를 실행 시킨다. (2) Runnable Interface 자바에서는 Thread 를 구현할 때 Thre..
이번에는 JPA Entity에서 이벤트가 발생할 때마다 특정 로직을 실행시킬 수 있는 @EntityListeners를 정리해보려고 한다. 예제 코드는 Spring boot와 Kotlin을 사용하여 작성하였다. JPA EntityListeners 란? 하이버네이트 문서에서는 JPA Entity에 이벤트가 발생할 때 콜백을 처리하고 코드를 실행하는 방법이라고 소개하고 있다. 이제 하이버네이트에서 지원하는 콜백 메서드들을 살펴보자. EntityListeners는 JPA Entity에 Persist, Remove, Update, Load에 대한 event 전과 후에 대한 콜백 메서드를 제공한다. 이번 글에서는 간단한 예제로 Update 하는 코드를 작성해보려고 한다. 예제 코드 @Component class U..
Springboot와 JPA를 사용하는 서비스에서 Hibernate SQL 쿼리 로그를 확인해보니 insert 쿼리가 단 건씩 발생하는 것을 보았다. 분명 saveAll() 메서드를 사용하고 있는 함수였지만 의도한 대로 동작하지 않았던 것이다. 발생한 쿼리는 아래와 같았다. Hibernate: insert into user (name) values (?) Hibernate: insert into user (name) values (?) Hibernate: insert into user (name) values (?) Hibernate: insert into user (name) values (?) Hibernate: insert into user (name) values (?) Hibernate: ins..
어느 날 땡땡이라는 API를 호출 시, 조건에 만족하는 모든 데이터를 뿌려주는 쿼리가 실행되는 것을 발견하였다. 프론트에서 모든 데이터를 받고 페이징을 처리하는 구조였던 것이다. 이런 구조는 데이터가 많이질수록 부하가 발생할 수 있는 구조이기 때문에 서버에서 페이징을 처리하는 구조로 변경하기로 했다. 페이징은 Offset과 limit을 사용하는 방식이 주로 사용되는데, 문제는 해당 API를 사용하는 웹 페이지에는 페이지 버튼이 존재하지 않았기 때문에 어떤 방법을 사용하여 페이징을 구현할까 고민을 하게 되었다. 현재 데이터를 보여주는 방식은 아래 사진처럼 화살표를 클릭하면 다음 데이터가 나오는 구조였다. 따라서 기존의 페이징 방식인 버튼(페이지 번호)을 사용하는 방식이 아닌 페이지 번호가 없는 No Off..
이번에 간단하게 Entity를 조회하는 API인데 성능이 생각보다 안좋은 이슈를 발견하게 되었다. 그래서 Entity를 확인해보니 OneToOne 관계를 사용하고 있었고 로그를 확인 했을 때 쿼리가 한 번이 발생하는 것이 아닌 무수히 많은 쿼리가 발생하는 것을 보았다. OneToOne 관계에서 지연로딩이 동작하지 않는다는 것은 인지하고 있지 못하였는데 이 기회에 한 번 정리해보려고 한다. (예제 언어는 자바가 아닌 필자에게 익숙한 코틀린으로 작성하였다. 자바 예제는 추후 추가할 예정이다.) 먼저 결론을 말하자면 JPA 구현체인 Hibernate 에서는 양방향 OneToOne 관계에서는 지연로딩이 동작하지 않는다. 정확하게는 테이블을 조회할 때 외래 키를 갖고 있는 테이블(연관 관계의 주인)에서는 지연로딩..