📘 Hibernate + log4jdbc: 완성형 SQL 로그 남기기와 포맷팅 적용안녕하세요.오늘은 Hibernate를 사용할 때 Hibernate 외부에서 발생하는 쿼리 로그가 출력되지 않거나, Hibernate 쿼리가 실행 가능한 완성형 쿼리로 보이지 않는 문제를 개선하는 방법에 대해 소개드리려 합니다.💡 배경저희 프로젝트는 기본적으로 Hibernate 기반의 JPA를 사용하고 있으며, 쿼리 로그는 Spring Boot의 application.yml 설정을 통해 다음과 같이 남기고 있었습니다:logging:level:org.hibernate.SQL:debugorg.hibernate.type.descriptor.sql.BasicBinder: trace이 설정을 통해 Hibernate가 생성한 SQL..

전체 글
🐏 final final 키워드는 이름 그대로 끝 이라는 뜻이다.변수에 final 키워드가 붙으면 더는 값을 변경할 수 없다.final을 지역 변수에 설정할 경우 최초 한 번만 할당할 수 있다. 이후에 변수의 값을 변경하려면 컴파일 오류가 발생한다.final 을 지역 변수 선언 시 바로 초기화 한 경우 이미 값이 할당되었기 때문에 값을 할당할 수 없다.매개변수에 final 이 붙으면 메서드 내부에서 매개변수의 값을 변경할 수 없다. 따라서 메서드 호출 시점에 사용된 값이 끝까지 사용된다.final 을 필드에 사용할 경우 해당 필드는 생성자를 통해서 한번만 초기화 될 수 있다. 🐏 static + finalpublic class FieldInit { static final int CONST_VAL..
스프링부트는 spring-boot-starter-validation 라이브러리를 넣으면 자동으로 bean validator를 인지하고 스프링에 통합 검증 로직을 모든 프로젝트에 적용할 수 있게 공통화하고 , 표준화한 것이 Bean Validation @Validated : 스프링 전용 검증 어노테이션 @Valid: 자바 표준 검증 어노테이션 검증 순서 1. @ModelAttribute 각각의 필드에 타입 변환 시도 1) 성공하면 다음으로 2) 실패하면 typeMismatch 로 FieldError 추가 2. Validator 적용(실제 min , max 등의 검증 기능) 바인딩에 성공한 필드만 Bean Validation을 적용 BeanValidator 는 바인딩에 실패한 필드는 BeanValidati..
김영한님의 자바 입문편 강의를 수강하고 제가 복습이 필요하다고 생각한 부분들에 대해서 정리한 글입니다. 🧐 배열 배열은 같은 타입의 변수를 사용하기 편하게 하나로 묶어둔 것이다. 배열 변수 선언int[] students; // 배열 변수 선언 배열 변수를 선언한다고해서 아직 사용할 수 있는 배열이 만들어진 것은 아니다. 배열 생성students = new int[5]; // 배열 생성 - 배열을 사용하려면 배열을 생성해야한다- new int[5]라고 입력하면 오른쪽 그림과 같이 총 5개의 int형 변수가 만들어진다. new는 새로 생성한다는 뜻이고, int[5]는 int형 변수 5개라는 뜻이다. 배열의 초기화new int[5] 라고 하면 총 5개의 int형 변수가 만들어진다. 자바는 배열을 생성..
현재 내가 개발을 하고 있는 프로젝트에서 팀원 분이 다음과 같은 이슈가 발생한다고 하셨다. 외부(최상단) 트랜잭션에서 a,b,c라는 로직을 수행하고 d라는 알림톡 발송 로직을 수행하고 있었는데, d라는 알림톡 발송 로직이 실패하더라도 외부 트랜잭션에서 호출하는 a,b,c 로직에 대해서는 정상적으로 커밋이 되길 바라셨는데 롤백이 되었던 이슈였다. 따라서 나는 알림톡 발송 로직을 수행하는 d의 트랜잭션 전파 옵션을 REQUIRES_NEW로 바꾸어서 테스트를 해보았는데도 a,b,c 로직은 여전히 롤백되었다.. 외부 트랜잭션 -> d(알림톡 발송로직 및 기타 로직) -> (실제 알림톡 발송 로직) 이렇게 비즈니스 로직이 구성되어있었는데, 이것에 대해 각각 A,B,C라고 언급하도록 하겠다. 작성된 코드를 보니, ..
위와 같은 엔티티에서 findByUserIdAndPopUpStoreId로 하면 User 테이블과 PopUpStore 테이블과 join을 하여 다음과 같은 쿼리가 실행된다. 내가 원하는 건 bookmark 테이블의 컬럼 값만 가지고 where절을 통해 조회를 하고 싶은데 보면 불필요한 join이 발생함을 알 수 있다. 이 불필요한 join문을 제거할 방법이 있는데, 그것은 where 절에 연관관계 엔티티를 넣어 조회하는 것이다. 위와 같이 Spring Data JPA findBy의 파라미터로 엔티티를 전달하면 다음과 같이 join문이 제거되고 내가 원하던 쿼리가 실행된다.
다음은 내가 Spring에서 지원하는 Pageable 인터페이스를 활용할 때, 여러 케이스를 시도하면서 얻었던 결론을 정리한 것이다.⚽ Pageable 정렬 동작 방식CASE 1) 조회하고자 하는 쿼리에 OrderBy (정적 정렬 조건)명시되어있을 때Querydsl을 사용한 메소드의 경우에는 클라이언트에서 sort에 파라미터 값 보내도 무시됨(Querydsl에서는 따로 정렬 쿼리 메소드를 구현해서 작업을 해주지 않는 이상 Pageable sort가 동작하지 않음)JPA에서 반환 타입이 Page이고, @Query 어노테이션으로 JPQL에 정적 정렬 조건을 넣는 경우 클라이언트에서 전달받은 sort 파라미터 추가돼서 정렬 조건으로 들어감 (JPQL 정적 정렬 + 클라이언트로부터 받은 sort 정렬 조건)파라..
이번에 완전 대량의 데이터는 아니지만, 적당하게 많은 데이터들을 받아서 인터페이스 테이블에 동기화를 해야 할 일이 생겼다. 그래서 insert 하는 방식으로, 매번 for문을 돌면서 save를 하기보다는 List에 엔티티 객체들을 담아두고 saveAll을 통해 새로운 트랜잭션 생성을 위한 비용을 줄이고, 성능을 높이려고 하였는데, 이 방식도 결국에는 단 건 쿼리로 insert 되는 바람에 내가 기대하던 바는 아니었다.따라서 다음 환경 설정을 통해 batch size를 지정하고 해당 size만큼의 데이터를 하나의 insert 쿼리로 처리하도록 하였다.spring: jpa: properties: hibernate: jdbc.batch_size: 100 order_in..
Querydsl을 이용해서 개발을 하다가 "java.time.LocalDateTime is not compatible with java.lang.String" 에러가 발생했다. 이 에러가 발생했던 이유로는, 조회했던 Entity의 컬럼이 LocalDateTime 타입이었는데, DTO에 매핑시키려고 했던 필드의 타입은 String이어서 발생했었다. DTO 필드 형태를 바꿔주면 간단히 해결되지만, 나는 외부 솔루션을 연동하기 때문에, 어쩔 수 없이 String으로 넘겨주어야했다. 따라서 조회할 때 LocalDateTime을 String으로 변환을 해줘야하는데, 찾아보니Querydsl에서 지원하는 Expressions와 MySQL의 DATE_FORMAT이라는 함수에 변환해줄 String 형식을 지정하면 바꿀 ..
⚽ 문제 상황개발하는 도중에 Swagger에 DTO의 필드 수정 사항이 반영이 제대로 되지 않았다. 다음과 같은 DTO 2개가 프로젝트 내부에 있었는데, 둘 다 이너클래스 명이 PopUpStore였다.@Getter@Builderpublic class GetOpenPopUpStoreListResponse { private List openPopUpStoreList; private int totalPages; private long totalElements; @Data @Builder @NoArgsConstructor @AllArgsConstructor public static class PopUpStore { private Long id; ..
어떤 프로젝트에 참여해서 소스 코드를 보다 보면, 어떤 메소드에는 @Transactional이, 또 어떤 메소드에는 @Transactional(readOnly=true) 어노테이션이 붙어있는 것을 종종 목격할 수 있다. 이번 글에서는 이 둘의 차이점과 @Transactional(readOnly=true)를 사용하는 이유에 대해서 알아보려고 한다. 우선 @Transactional(readOnly=true)에 대해 언급하기 이전에트랜잭션과 @Transactional이 무엇인지부터 간단하게 알아보자. ⚽ 트랜잭션과 @Transactional 어노테이션트랜잭션은 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위이다. 예시를 들자면 춘식이와 루피가 돈을 주고 받는 상황이 있다고 가정..
Jackson사용 시 primitive boolean주의점 개발을 하면서 DTO 클래스의 필드를 정의할 때, boolean 타입을 사용했다. 필드 이름을 isXXX 형태로 작성했는데, @RequestBody 를 사용하는 컨트롤러 단계에서 true 보내는데 계속 false로 서버에 전달되는 문제가 발생하였다. 그 이유는 다음과 같다 JSON 변환 시 Getter를 사용하기 때문에 Getter를 무조건 생성해야하는데, lombok 의 @Getter 를 사용하면 boolean 필드의 getter를 만들 때 getXXX 처럼 만드는게 아니라 isXXX 처럼 메서드명을 짓는다. 따라서 정상적인 getXXX 형태가 아니기 때문에 제대로 역직렬화가 되지 않는 것이다. 이를 해결하기 위한 방법으로는 다음 방법들이 ..