본문 바로가기

BE18

JPA에서 soft delete 처리하기 (@Where, @Filter) JPA에서 soft delete 처리하는 방법에 대해 알아보겠습니다. hard delete와 soft delete 데이터를 삭제할 때 크게 hard delete(물리 삭제)와 soft delete(논리 삭제) 두 가지 방법이 있습니다. hard delete hard delete는 SQL의 delete 명령어를 사용하여 직접 데이터를 삭제하는 방법입니다. hard delete의 경우 delete 쿼리가 발생하기 때문에 삭제 후 DB에서 조회할 수 없습니다. 장점으로 select시 성능이 soft delete보다 상대적으로 좋습니다. 단점으로 삭제된 데이터를 복구하기 어렵고, 비즈니스에 데이터를 활용할 수 없습니다. soft delete soft delete는 SQL의 update 명령어를 사용하여 특정 컬.. 2023. 2. 1.
ApplicationEventPublisher를 활용하여 서비스 강결합 문제 해결하기 ApplicationEventPublisher를 활용하여 트랜잭션 강결합 문제를 해결하는 방법을 알아보겠습니다. 프로젝트를 진행하다 보면 의도치 않게 서비스끼리 강결합되는 문제가 발생합니다. 아래 예시가 있습니다. UserService @Service @RequiredArgsConstructor @Transactional public class UserService { private final UserRepository userRepository; private final MailService mailService; public Long create(UserReqDto dto) { User user = userRepository.save(User.builder() .email(dto.getEmail()).. 2023. 1. 31.
Spring에서 AWS RDS MySQL Replication 적용하기 현재 진행하고 있는 개인 프로젝트에서 DB로 AWS RDS MySQL 한 대만 사용하고 있다. 캐시 서버를 운용하여 DB에 가해지는 부하를 줄인다고 하더라도 트래픽의 증가에 따라 한 대 뿐인 데이터베이스에 장애가 발생할 가능성이 있다. 이에 이러한 상황에 대비하기 위해 AWS RDS 환경에서 MySQL Replication을 적용해보았다. 이해를 돕기위해 실제 프로젝트에 사용한 깃허브 레포지토리의 패키지 주소를 공유합니다. 아래 주소를 참고해주세요. https://github.com/ProjectShallWe/shallwe-backend/tree/main/src/main/java/com/project/board/global/datasource AWS RDS 설정 기존 RDS의 읽기 전용 DB 하나를 생성.. 2022. 11. 29.
Querydsl을 활용한 조건 검색 기능 개선 프로젝트 내 검색 기능을 동적 쿼리를 활용해 개선해보고 싶어 개인 프로젝트에 Querydsl을 사용하기로 결정했다. 기존 코드의 문제점 PostController // PostController.class @RestController @RequiredArgsConstructor @RequestMapping("/api/post") public class PostController { private final PostService postService; // controller code... @GetMapping("/search") public Page getPostsBySearchKeywordInBoard( @RequestParam("board") Long boardId, @RequestParam Inte.. 2022. 8. 7.
스프링 S3 연동 오류: No valid instance id defined 오류org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.cloud.aws.core.env.ResourceIdResolver.BEAN_NAME': Invocation of init method failed; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'stackResourceRegistryFactoryBean' defined in class path resource [org/springframework/c.. 2022. 7. 27.
본인 확인은 어떤 layer에서 이루어져야 할까? 개인 프로젝트를 진행하며 고민한 문제가 있다. 현재 프로젝트에서 게시판에 작성된 글이나 댓글을 update하거나 delete할 때, 작성한 본인 혹은 관리자만 삭제할 수 있게 만들고 싶었다. 1. Service Layer // PostService.class @Service @RequiredArgsConstructor public class PostService { private final UserRepository userRepository; private final PostRepository postRepository; // Service code... @Transactional public Long update(String email, Long id, PostUpdateRequestDto updat.. 2022. 7. 22.
@Column(nullable = false) 와 @NotNull 중 무엇을 사용해야 할까? 개인 프로젝트 도중 Entity에 DB 제약조건을 적용하다가 궁금점이 생겼다. @Column(nullable = false) // User.java @Entity @Table(name = "user_table") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @EntityListeners(AuditingEntityListener.class) public class User extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(unique = true, nullable = false) @Email private Strin.. 2022. 7. 18.
유클리드 호제법으로 최대공약수 최소공배수 구하기 개념 2개의 자연수 a,b에서 a를 b로 나눈 나머지를 r이라 한다면 (단 a > b), a와 b의 최대공약수는 b와 r의 최대 공약수와 같다. 이 성질에 따라 b를 r로 나눈 나머지 r`를 구하고, 다시 r을 r`으로 나눈 나머지를 구하는 과정을 반복하여 나머지가 0이 되었을 때 나누는 수가 a와 b의 최대공약수이다. 최대공약수 // a > b 일 때, int gcd(int a, int b) { while (b > 0) { int tmp = a; a = b; b = tmp % b; } return a; } 반복문을 사용하여 위와 같이 표현할 수 있다. // a > b 일 때, int gcd(int a, int b) { if (a % b == 0) { return b; } return gcd(b, a%b.. 2022. 7. 17.
Math 클래스 메서드 정리 오늘은 유용하게 사용되는 Math 클래스 메서드들을 정리하려한다. sqrt() 제곱근을 구한다. int num = 16; System.out.println(Math.sqrt(num)); /* double Math.sqrt(double) 출력 결과: 4.0 */ random() 0과 1사이의 실수값을 출력한다.(0 포함) System.out.println(Math.random()); /* double Math.random() 출력 결과: 0.11231300330818705 */ abs() 절대값을 구한다. double num = -15.5; System.out.println(Math.abs(num)); /* double Math.abs(double) 출력 결과: 15.5 */ ceil() 소숫점이 있을 때.. 2022. 7. 14.
String 클래스 메서드 정리 String 클래스는 참조 타입으로 여러 메서드들을 내장하고 있다. charAt() 인덱스에 위치한 문자를 반환하는 메서드이다. String text = "abcdef"; System.out.println(text.charAt(2)); /* char string.charAt(int index) 출력 결과: c */ concat() 문자열을 뒤에 결합한다. String text = "abcdef"; System.out.println(text.concat("g")); /* String String.concat(String s); 출력 결과 : abcdefg */ contains() 문자열을 포함하고 있는지 확인한다. String text = "abcdef"; System.out.println(text.con.. 2022. 7. 14.
yaml 파일을 그룹으로 관리하기 yaml 파일을 그룹으로 관리하는 법을 알아보자. application-dev.yml application.yml 프로젝트를 진행하다 보니 yaml 파일 내 외부에 유출되서는 안되는 정보들이 늘어났다. 내 프로젝트는 RDS나 S3등 다양한 AWS 서비스들을 사용하여 connection 정보들이 yaml파일 내 산재해 있었다. 이에 외부에 공개해서는 안되는 yaml 파일들을 모듈화시켜 깃허브에 올라가지 않게 관리하기 위해 spring.profiles.group 옵션을 사용하였다. application.yml application-dev.yml application-rds.yml .gitignore spring.profiles.group 옵션은 jar파일 실행시 그룹화된 프로필 내의 모든 설정 정보를 전달한.. 2022. 7. 9.
Springboot에서 Redis Cache 적용하기 (2022.12.05 최종 수정) 개인 프로젝트를 진행하던 중 페이지 별로 반복 호출되는 API들이 있었다. 대표적으로 게시판 별 추천글 목록, 전체 인기글 목록 등이 있었다. 이러한 반복적으로 호출되는 쿼리를 줄여 부하 분산을 하기 위해 프로젝트에 Spring Cache를 도입하였다. 왜 Redis를 선택했을까? 캐시는 크게 로컬 캐시와 글로벌 캐시 두 가지가 있다. 로컬 캐시는 각각의 WAS 내부 저장소에 캐시를 저장하는 방식이다. WAS의 리소스를 사용하기 때문에 속도는 빠르지만 Scale-Out 방식의 서버 확장시 서버간 데이터 공유가 안되어 일관성 문제가 발생할 수 있다는 문제가 있다. 글로벌 캐시는 별도의 캐시 서버를 두고 WAS에서 캐시서버를 참조하는 방식이다. 캐시 데이터를 얻을 때 마다 .. 2022. 6. 27.
스프링 스케줄러(@Scheduled) 사용하는 법 스프링 스케줄러를 사용하는 법에 대해 알아보자. @Scheduled 우선 스프링 스케줄러를 사용하기 위해서 간단한 세팅을 해주어야 한다. @Configuration @EnableScheduling public class ScheduledConfig { } 1. 스케줄러 설정 클래스를 만들고, @EnableScheduling 어노테이션을 붙여준다. @Scheduled(fixedDelay = 5, initialDelay = 3000) public void helloWorld() { System.out.println("Hello World"); } 2. 사용할 메서드 위에 @Scheduled 어노테이션을 붙이고, 언제 작업을 수행할지 속성을 설정한다. 속성 cron : cron 표현식을 지원한다. (자세한 내.. 2022. 6. 23.
스프링 테스트 에러: JPA metamodel must not be empty! 오류java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132) at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124) at org.springframework.test.context.support.DependencyInjectionTestExecut.. 2022. 2. 21.
외부 API 파싱하기 (JSON) 기업 협업 프로젝트중 농장 실사 방문 예약 기능을 만들 일이 있었다. 기업의 요구사항으로 기업측에서 하루에 한 농가만 방문할 수 있게 예약 시스템을 구현해야했다. 이에 농장 입점 신청자가 입점 3단계를 시작하면 서버에서 예약 불가능한 날짜를 return해주어야 했다. 예약 불가능한 날짜 중 주말은 자체적으로 구현할 수 있었지만, 공휴일은 자체적으로 구현하는 것이 효율적이지 않다고 생각했다. 이에 공공데이터 포털에서 제공하는 한국천문연구원_특일 정보를 활용하기로 했다. API 파싱하기 우선 공공데이터포털 사이트에 들어가 로그인 후 API 사용 신청을 해주어야한다. 사용신청을 완료하면 위와 같은 화면을 볼 수 있다. 여기서 우리는 일반 인증키(Encoding)를 복사하여 아래 코드의 '서비스키' 에 붙여넣기.. 2022. 2. 7.
스프링 부트 실행 환경 분리 스프링에서 실행 환경을 분리하는 법에 대해 알아보자. // application.yml # H2를 이용한 local 개발 단계에서 사용 spring: datasource: driver-class-name: org.h2.Driver url: jdbc:h2:tcp://localhost/~/process; username: sa password: # MySQL을 이용한 배포 단계에서 사용 #spring: # datasource: # driver-class-name: com.mysql.cj.jdbc.Driver # url: jdbc:mysql://{url} # username: {username} # password: {password} jpa: hibernate: # H2를 이용한 local 개발 단계에서 사.. 2022. 2. 2.
@PathVariable, @RequestParam는 각각 언제 사용해야 할까? 클라이언트에서 URL에 parameter를 같이 전달하여 HTTP request를 요청하는 경우가 있다. 이경우 스프링에서는 controller단에서 @PathVariable과 @RequestParam을 사용해 처리한다. @RequestParam http://localhost:8080/api/post/search?board=1&page=1 위의 URL의 경우 parameter의 key와 value를 쿼리 스트링으로 전달하는 방식으로, 이런 경우 @RequestParam을 사용하여 처리한다. @GetMapping("/api/post/search") public Page getPostsBySearchKeywordInBoard( @RequestParam("board") Long boardId, @Request.. 2022. 1. 20.
Lombok 어노테이션 정리 @Getter, @Setter // lombok 적용 전 public class User{ private Long seq; private String email; private String password; private String nickname; public String getSeq() { return seq; } public String getEmail() { return email; } public String getPassword() { return password; } public String getNickname() { return nickname; } public void setSeq(Long seq) { this.seq = seq; } public void setEmail(String .. 2022. 1. 15.