이전에 LocalCache 를 사용해서 Cache 서비스를 구현한 적이 있었습니다. 이번에는 이후에 MSA 서비스 확장성을 고려해서 Global Cache 를 사용하자는 요구사항이 나와서 Redis 를 사용해 Global Cache 를 구현해보겠습니다. Local 환경에 Redis 설치와 실행이 끝났다는 가정하에 쓴 글입니다. 아직 설치가 되지 않았다면 해당 블로그를 참고해주세요. (mac) https://wlswoo.tistory.com/44 🧤 Config build.gradle implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot..
🫡 요구사항 촬영장비 렌탈 플랫폼 DayFilm 의 아이템(상품) 도메인을 맡아 서버 개발을 진행했다. 아이템을 등록할 때, 여러 장의 사진과 함께 등록해야 하는 요구사항이 있었고 배포 Tool로 AWS 를 선택했기 때문에 S3 Bucket 에 등록하기로 결정하였다. 🫡 엔티티 Item.class @Entity @Builder @NoArgsConstructor @AllArgsConstructor @Table(name = "ITEM_TABLE") @Getter public class Item { @Id @GeneratedValue @Column(name = "item_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="sto..
스프링은 스프링 컨테이너 ( Ioc 컨테이너 , DI 컨테이너라고도 불린다. ) 를 통해 객체를 빈에 등록하고 생명주기를 관리한다. 때문에 비즈니스 로직에 맞게 알맞은 생명주기를 선택해 적용하는 것은 매우 중요하다. 어떻게 빈을 생성하고 관리하고 소멸할지에 대해서는 백엔드 개발자에게 매우 민감하고 중요한 문제이기 때문에 스프링의 빈 관리 특징들을 이해해보자. 싱글톤 스프링의 기본 디자인패턴은 싱글톤이다. 싱글톤 디자인 패턴은 스프링 애플리케이션의 시작부터 종료까지로 빈의 생명주기를 관리한다. 즉 애플리케이션이 실행될 때 스프링 컨테이너에서 해당 빈 객체들을 생성하고 의존관계를 맺어준다. 또한 애플리케이션이 종료될 때 빈 객체의 소멸 메소드를 실행해 빈 객체의 소멸까지 보장해준다. 또한 싱글톤 디자인 패턴..
Spring Boot starter 에 내장되어있는 tomcat 은 기본적으로 Multi Thread 환경을 지원한다. 덕분에 클라이언트의 요청을 처리하고 있는 도중 새로운 클라이언트 요청이 들어왔을 경우, 이전 요청이 끝날 때까지 기다리지 않고 다른 쓰레드가 해당 요청을 처리한다. 자칫 잘못하면 데이터의 일관성이 무너질 수 있기 때문에 해당 쓰레드간의 동기화 과정은 매우 중요하다. 보통 멀티 쓰레드 환경에서 하나의 사용자의 요청을 하나의 쓰레드로 처리한다. 동일한 ip의 요청일 때에는 같은 쓰레드로 처리할 수 있긴하지만, 일반적인 경우에는 하나의 요청에 하나의 쓰레드가 붙는다. 그러나 매번 요청이 생성되고 끝날 때마다, 쓰레드를 생성하게 되면 생성하고 삭제하는 코스트가 발생한다. 스프링에서는 이러한 코..
이전 포스팅에서 Cache 를 구현할 수 있는 다양한 방법에 대해서 알아보았다. 각 방법의 특징을 서술하고 본 프로젝트에 HashMap 을 적용해 Cache 를 구현하는 이유에 대해서도 설명하였다. 이번 포스팅에는 HashMap 으로 어떻게 Cache 를 구현하는지에 대해 알아보겠다. https://daisyit.tistory.com/43 : 캐시 전략 비교 🌊 Key 설정 우선 캐시에서 가장 중요한 건 key 값의 설정이다. key 값을 통해 원하는 value 에 접근하기 때문에, 어떻게 key 값을 설정할 것인지 명확하게 구분지어야 한다. 해당 프로젝트는 바라보는 데이터베이스 소스인 datasourceKey 값과 실행할 쿼리 sql 값에 따라서 데이터가 달라지기 때문에 이 두 변수를 key 값으로 지..
인턴에서 백오피스 개발을 하던 도중, 같은 데이터를 계속 조회하는 상황이 빈번하게 발생했다. 데이터 수도 꽤 많았기 때문에 매우 비효율적이라고 판단했고, Cache 를 적용해 이전에 조회한 데이터를 다시 데이터베이스에서 조회하지 않게 설계하였다. JDBC를 사용해 커넥션을 연결하고, 쿼리를 날린 후, 데이터베이스에서 다시 가져와 커밋하는 코스트가 매우 높기 때문이다. 캐시를 사용해야겠다고 마음 먹은 후, 요구사항에 맞는 캐시전략을 사용해야했다. 이번 프로젝트의 요구사항은 서버는 하나이며, 캐시의 키 값으로 구분지을 데이터 종류가 많지 않았다. 대시보드의 각 서브 메뉴마다 데이터가 존재했기 때문에, 서브메뉴 * 쿼리 파라미터 개수만큼 데이터 종류가 나왔기 때문이다. Redis, EHcache, HashMa..
이전 포스팅에서는 순수 JDBC 를 사용해 사용자가 직접 트랜잭션을 제어하고 관리하는 방법에 대해서 알아보았다. 근본적이고 "유일한" 방식은 틀림없지만, 매번 연결할 때마다 선언하고 관리하는건 비효율적이다. 때문에 스프링에서는 @Transactional 어노테이션을 제공해 코드의 중복을 없애고 편리하게 관리할 수 있도록 지원한다. 하지만 동작원리는 똑같다. - 코드예시 @Transactional public UUID saveUser(User user) { log.debug("User(service) : 새로운 유저를 저장합니다. {}", user); return userRepository.save(user); } 다음과 같은 새로운 유저를 저장하는 예시 코드가 있다. 기존 스프링에서는 Spring Con..
인턴 근무 중, JPA를 사용하는 것이 아닌 JDBC 를 사용해 직접 데이터베이스 커넥션을 연결해야했다. 평소에 JPA 어노테이션을 즐겨 사용했던 나는 이번 계기로 @Transaction 어노테이션의 정확한 동작원리와 JDBC 를 사용해 RDBMS를 다룰 때 트랜잭션 관리를 어떻게 하는지 궁금했해 알아보기로 했다. - 예시코드 public String SampleEndPoint(String datasourceKey, String sql) { HikariDataSource datasource = getDataSourceByKey(datasourceKey); //1 Statement st = null; Connection con = null; Integer result = null; String rtnVal..