본문 바로가기

Programing/Framework

(70)
[JOOQ] MySQL JDBC batch 벤치마킹 batch 처리에 대한 의견 코드리뷰를 하다 jdbc의 batch 처리를 하면 성능 효과를 얻을 수 있을 것 같다는 성준님의 의견이 있었다. executeBatch 를 이용한 방법입니다. (e.g Batch Processing in JDBC atBaeldung) 단일 DELETE N 건 실행 대비, 성능상 이점이 있습니다. 평소 성준님은 최적화에 대해 M.A.Jackson의 말을 인용하시던 분이었다. 최적화를 할 때는 아래의 두 규칙을 따르라. 규칙1: 하지마라 규칙2: (전문가들만 따를 것) 아직은 하지마라 - 완벽히 명료한, 최적화되지 않은 해답을 얻을 때까지는. - M. A. 잭슨(M. A. Jackson) 사실 네트워크 round-time을 생각해본다면 상식적으로 한번에 batch로 보내는 것이 ..
[Spring MVC] HandlerMethodArgumentResolver 구현하기 가끔 Controller 에 특정 타입의 값을 자동으로 받고 싶을 경우가 있다. path가 "foo/{a}/{b}" 인데 a 랑 b값을 aggregation 해서 특정 객체로 만들고 싶은데 프레임워크에게 시키고 싶은 것이다. 이럴 경우 @PathVariable 에 대한 메서드 인자 Resolver 를 만들어주면 해결이 가능하다. 기본적으로 @PathVariable Resolver는 두 가지가 있다. PathVariableMethodArgumentResolver PathVariableMapMethodArgumentResolver 위의 경우는 파라미터의 이름이나 @PathVariable 에 지정된 value 의 값을 매핑시켜준다. 가끔 타입 변환이 필요한 경우에는 conversionService에게 타입 변..
[JPA] @Converter 는 어떻게 동작할까? 지니님이 기본 데이터 타입과 String 등을 enum 으로 바꾸는 작업을 진행하셨다. 대부분은 아래와 같이 @Enumerated 으로 enum의 이름을 사용하도록 작업을 했다. import lombok.Getter; import lombok.Setter; import javax.persistence.*; @Entity @Table(name = "TEST") @Getter @Setter public class TestEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "SEQ") private Integer id; @Column(name = "ACTION_TYPE", length = 100) @Enumerated(..
[스프링] 생성자가 private 일때 스프링은 객체는 어떻게 만들까? 어제 지니님의 요청한 코드리뷰를 하다 아래와 같은 코드를 발견했다. (이름은 적절히 각색하였습니다.) import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Getter @Setter @NoArgsConstructor(access = AccessLevel.PRIVATE) class ReceiptProperties { private String receiptUrl; } 내가 하려는 이야기는 lombok을 썼다는 것이 아니고 왜 private 생성자로 결정 했을까가 포인트이다. 위의 코드를 일반 자바코드로 풀어쓰면 아래와 같다. class ReceiptProperties { p..
[Spring] FieldError의 계층구조 스프링 Controller에서 파라미터 에러가 나면 BindingResult 로 바인딩 결과를 받아 올 수 있다. @RestController @RequestMapping(value = "/some") public class SomeController { @PostMapping(value = "/thing") public ResponseDto ready(@RequestBody @Valid Params params, BindingResult bindingResult) { if (bindingResult.hasErrors()) { // ... } 만약에 결과를 받지 않을 경우 @Valid에서 실패한 것은 MethodArgumentNotValidException 예외가 던져진다. 이 예외 안에는 위의 Cont..
[JPA] H2 테스트 코드에서 createdAt 필드가 없던 이유 코드리뷰에서 save 를 반복하며 직접 iteration을 도는 것보다 saveAll 을 호출하는 것이 성능상 더 좋을 것 같다는 comment가 달렸다. 정말로 그럴지 테스트 해보기 위해 테스트코드를 짰다. 사실 테스트라기 보다는 리스트로 데이터를 saveAll을 수행시 어떻게 동작하는지 디버깅을 해보려는 것이었다. @DataJpaTest @ActiveProfiles("test") class RequestRepositoryFunctionalSpec extends Specification { @Autowired RequestRepository sut def "saveAll 로 처리하면 성능상 이점이 있을것이다 by yh"() { given: List entities = [ getDummyEntityWit..
[JPA] N+1 문제 면접 때 자주 나오는 단골 문제 N+1 Ploblem이다. 내가 맡고 있는 팀은 그동안 테이블을 비정규화 해서 사용을 하고 있었기에 엔티티가 관계를 맺고 있지 않아서 이 문제를 만날 일이 없었다. 이번에 현금영수증 관련 기능을 개발하면서 그동안 중복저장하던 데이터를 좀 효율적으로 사용하기 위해 정규화를 해서 테이블을 쪼갰다. 드디어 N+1 문제를 만났다. EntityA, EntityB 가 있는데 EntityB 안에 EntityA를 포함하고 있다고 치자. FetchType이 EAGER 라면 EntityB를 조회하면 자동으로 EntityA 를 조회하는 쿼리까지 수행이된다. 조회하는 EntityB의 개수가 10개라면 각각 관련된 EntityA까지 추가로 +10회 조회가 되어 총 11회의 조회가 발생한다. 그렇..
[Spring JPA] 멀티컬럼 - 쿼리메소드 vs @Query 도비님이 코드리뷰 PR을 주셨다. 기존에 query method로만 사용을 했는데 @Query 를 사용하여 왜 그랬는지 궁금했다. 알고보니 특정 컬럼에 대하여 or 조건으로 결합이 되었던 것이 이유였다. 예를 들어 (t.a = 'abc' or t.a = 'bcd') and ... 같이 우선적으로 적용해야 하는 or가 있는 경우였다. 물론 결합법칙으로 (A OR B) AND C 를 A AND C OR B AND C 로 풀 수는 있지만 trade-off 비용이 더 안좋았을 거라 생각이든다. 다른 생각 하지만 JPA 객체지향이 아닌 쿼리지향으로 사용하고 있지 않는가 하는 생각을 하게 되었다. query method가 점점 길어지고 복잡해지고 있다면 쿼리지향을 하고 있는가 생각해 보는 점검의 시간(냄새)으로 생..