개발 일지 168

Controller 내부 API 요청 메소드에 트랜잭션 적용

위 코드는 기존에 작성되었던 코드이다. 컨트롤러 내부에서 dto를 엔티티 객체로 변환하고 변환된 객체를 service 로직에서 사용하고 있다. 이렇게 쿼리가 실행된다면 발생하는 문제점이 데이터의 안전성이 보장되지 않는다는 것이다. 예를 들어, service 클래스의 createCv가 실행되어 새로운 Cv가 생성되고 repository에 저장되었는데 아래 injectLowDomain에서 실패하게 되면 작업은 종료되어 적절한 응답을 주지 못했지만 저장소에는 새로운 Cv가 있을 것이다. 즉, 데이터의 일관성을 보장하기 위한 작업이 필요했고 helper라는 클래스를 만들어서 트랜잭션을 적용시켜줬다. 트랜잭션은 한 번에 실행되어야 하는 일련의 연산들을 모아놓은 것이다. 예를 들어, 여러 개의 작업이 실행되는 경우..

String concatenation as argument to 'StringBuilder.append()' call

인텔리제이로 알고리즘 문제를 풀던 도중 index 라는 변수를 줄 별로 출력하기 위해 다음과 같이 코드를 작성하니까 노란 밑줄이 생겼다. 인텔리제이가 다음과 같이 친절하게 교체할 것을 권장하면서 이유를 말해줬다. 두 코드는 사실 동일한 결과를 만들어준다. 하지만 수정된 코드를 권장하는 이유는 해당 방법이 성능 면에서 더 효율적이기 때문이다. sb.append(index + "\n"); 는 index 와 "\n"을 연결한 후에 그 결과를 StringBuilder에 추가한다. 따라서 연결하는 과정에서 연결 연산자인 '+' 를 사용하여 작업을 수행한다. 하지만 sb.append(index).append("\n"); 는 index를 StringBuilder에 추가한 다음 "\n" 문자열을 주가한다. 따라서 중간..

개발 일지/Java 2023.06.04

BufferedReader close() 사용 이유에 대해

알고리즘 문제를 풀면서 문득 생긴 궁금증이 있었다. 'BufferedReader를 사용해서 입력을 받고 실행하면 굳이 close()를 사용하지 않아도 정상적으로 컴파일 되는데 close()를 사용하지 않아도 되는가?' 찾아 본 결과, BufferedReader의 경우 close() 메소드를 명시하지 않아도 가비지컬렉터에 의해 BufferedReader가 자동으로 정리된다고 한다. 하지만 프로그램이 오랫동안 실행되거나 대용량의 데이터를 처리하는 경우에는 버퍼링된 데이터가 모두 출력되지 않거나 리소스가 해제되지 않을 수 있기 때문에 close()를 호출하는 것이 좋다. 이렇게 함으로써 버퍼를 비우고 안전하게 해제하여 메모리 누수나 시스템 리소스 부족 문제를 방지할 수 있다. 물론 가비지컬렉터가 적절하게 처리..

개발 일지/Java 2023.05.31

data.sql 초기화 설정 후 Error creating bean with name 'dataSourceScriptDatabaseInitializer' 에러

진행 중인 프로젝트에서 데이터 값을 초기 설정하고 싶어서 data.sql을 만들고 설정을 해줬더니 이런 에러가 발생했다. data.sql Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource Table "SKILL_STACK" not found; SQL statement: 해결 과정 시도 1. 테이블이 없다?.. yml 파일에 ddl-auto를 create로 설정해줬는데 그럼 테이블이 생겨야 하는 거 아닌가.. 라는 생각에 mysql을 확인해보니 테이블은 있었다. 직접 쿼리를 작성해서 테이블을 만들어주고 ddl-auto를 update로 변경 후 재실행했다. -> 실패 시도 2. 찾아..

[Gradle] build와 bootJar의 차이

Spring rest docs를 포함하여 테스트를 진행하고 html 파일을 만들기 위한 작업을 진행하던 중 build랑 bootJar 둘 다 html 파일을 만들어주는데 왜 둘로 나뉘어 있는걸까? 둘의 차이점은 무엇일까? 하는 궁금증이 생겨서 찾아보았다. 먼저 Gradle build와 Gradle bootJar는 모두 Gradle 빌드 도구를 사용하여 소프트웨어를 빌드하는 프로세스를 의미한다. 둘의 큰 차이를 보면 build는 모든 테스트 실행, 프로덕션 아티팩트 생성 등 모든 것을 구축하기 위한 것이고 bootJar는 Spring Boot 애플리케이션을 실행 가능한 JAR 파일로 패키징하는 특정한 빌드 프로세스만 수행하는 것이다. 즉, Gradle build는 프로젝트의 빌드와 관련된 모든 작업을 수행..

[AWS] Amazon Relational Database Service Provisioned Storage 비용

AWS로 서버를 설정하고 배포한 후 청구서에 비용이 조금씩 올라가기 시작했다. $0.131 per GB-month of provisioned GP3 storage running MySQL 이 녀석이 문제였다. 지금은 $0.00 per GB-month of provisioned GP2 storage under monthly free tier 가 적용되어 있지만 처음에는 적용되지 않았었다. 큰 금액은 아니었지만 분명 모든 설정을 freetier로 적용한 것 같은데 왜 요금이 계속 청구되는 거지? 하는 궁금증에 수많은 블로그를 찾아봤었다. 프리티어에 관한 많은 내용들이 있었지만 요금이 청구되는 해당 녀석에 대해서는 프리티어 설정에 대한 특별한 내용이 없었고 AWS에 직접 문의해 봤다. 결론부터 말하면, RDS..

개발 일지/etc 2023.05.17

[Spring Security] WebMvcTest 에서 401/403 에러 해결하기

slice 테스트로 controller의 post 테스트 로직을 작성하고 실행했더니 401 Unauthorized 에러가 발생했다. test 로직에서도 post 요청을 할 때 권한을 같이 넘겨줘야 한다는 것 같은데, WebMvcTest가 컨트롤러 테스트할 때 스프링 시큐리티가 자동으로 구성하는 Configuration 파일들을 불러와서 그렇다고 한다. 해당 문제는 다음과 같이 임의의 UserDetails를 만들어서 해결할 수 있다. @WithMockUser @Test public void postCvTest() throws Exception { } 또는 다음과 같이 excludeFilters를 활용해서 해당 Configurer를 회피하는 방법도 있다. @WebMvcTest(value = CvControl..

[Spring] Mapstruct 클래스타입 변환 / N:M 관계 매핑 에러

Mapstruct는 Builder를 통해 손수 객체 간 변환을 할 필요 없이 간단하게 변환을 적용해 주는 라이브러리이다. 평소 코드를 작성하면서 Dto 와 Entity 간에 변환이 필요할 때면 mapstruct를 이용해서 작업을 진행했고 이번에도 mapstrurct를 통해 매핑을 하는데 에러가 발생했다. Dto 필드가 많아서 문제가 발생한 코드를 하나 가져와보면, 아래 이너 클래스는 원시타입이 아니라 ProjectDto.Add 클래스 타입의 list를 필드로 갖고 있다. @Getter public static class Post { private List projects; } ProjectDto.Add 또한 내부에 클래스 타입의 List를 가지고 있다. @Data public static class Ad..

[JPA] @ElementCollection

JPA에서 @ElementCollection 애너테이션은 관계형 데이터베이스에서 값 타입을 컬렉션으로 매핑하기 위해 사용된다. 이를 통해서 개체에 속하는 값들을 한번에 모아서 저장할 수 있다. 어 그러면 그냥 Entity에 List를 만들어서 값을 저장하면 되는 거 아닌가?? 안된다. 관계형 데이터베이스는 일반적으로 컬렉션을 담을 수 있는 구조를 가지고 있지 않기 때문에 @ElementCollection 애너테이션을 통해서 값 타입 컬렉션을 매핑하는 것이다. 다음과 같은 경우에 해당 애너테이션을 사용할 수 있을 것이다. 예를 들어, 주문 엔티티는 여러 개의 주문 상품을 포함할 수 있지만 주문 상품 자체는 엔티티로서의 의미가 없는 값 타입일 것이다. 이런 경우에 엔티티를 또 사용해서 @OneToMany로 ..

[Java] @NotNull / @NotEmpty / @NotBlank

DTO에 유효성 검사를 적용하던 도중, 값이 비어있지 않도록 설정하기 위해 사용하는 애너테이션이 여러 개인 것을 확인했다. 모두 값이 비어있는 것을 허용하지 않는 애너테이션인데 왜 여러 개로 나뉘어 있을까라는 의문이 들어 알아보게 되었다. 먼저, @NotNull, @NotEmpty, @NotBlank 모두 프로그래밍에서 사용되는 데이터 유효성 검사에 관련한 애너테이션이다. 이 애너테이션들은 공통적으로 데이터가 null 인지 확인하고 추가적으로 공백 여부를 확인하느냐 마냐에 차이점이 있었다. @NotNull 데이터가 null 인지만 확인하는 애너테이션이다. 데이터가 null일 경우 유효성 검사를 통과하지 못하며, null이 아닌 경우에만 유효성을 갖는다. @NotEmpty 데이터가 null이 아니며, 길이..

개발 일지/Java 2023.04.18