본문 바로가기
Blog/TIL

[240523] 배워도 배워도 끝이 없네

by 코젼 2024. 5. 23.
728x90
반응형

🔶코딩 테스트 완전 정복

🔶스프링 데이터 JPA

🔶Querydsl


목차

     

     

    / 오늘의 TIL /


    코딩 테스트 완전 정복

    코딩 테스트 풀 때 의사코드를 꼭 적고나서 구현을 시작하자.

    조건문에 의해 조기 종료할 수 있으면 바로 return한다.

    조건문으로 예외 처리한다. (null, 값이 비어있는 경우...등등 return)

     

    정렬할 때, sort() API를 사용하면 O(NlogN)의 시간 복잡도를 가진다.

    자바에 유용한 표준 API들이 많다.

    배열, 컬렉션을 스트림으로 변환하면 반복문을 사용하지 않고 컬렉션의 데이터를 배열에 담아서 반환하거나 특정 조건에 따라 필터링하는 등 코드의 양을 줄이고 가독성을 향상시킬 수 있다.

    //중복 값 제거
    Integer[] result = Arrays.stream(arr)
    	.boxed() //레퍼런스 타입, Integer로 변환
        .distinct()
    	.toArray(Integer::new);
        
    //내림차순 정렬
    Arrays.sort(resut, Collections.reverseOrder()); //인수가 없으면 기본값은 오름차순
    
    //int 배열로 변경 후 반환
    return Arrays.stream(result)
    	.mapToInt(Integer::intValue)
        .toArray();
    //중복 값 제거, 내림차순 정렬
    TreeSet<Integer> set = new TreeSet<>(Collections.reverseOrder());
    
    for (int num : arr) {
    	set.add(num);
    }
    
    //int형 배열에 담아서 반환
    int[] result = new int[set.size()];
    for (int i=0; i<result.length; i++) {
    	result[i] = set.pollFirst();
    }
    return result;

     

    패턴 반복

    i % pattern[j].length로 패턴을 반복시킬 수 있다.

    1234512345...

    for (int i=0; i<answers.length; i++) {
        for (int j=0; j<pattern.length; j++) {
            if (answers[i] == pattern[j][i % pattern[j].length]) {
                scores[j]++;
            }
        }
    }

     

    stream - max 값 구하기

    OptionalInt로 반환되기 때문에 getAsInt()로 변환해주어야 한다.

    int maxScore = Arrays.stream(scores).max().getAsInt();

     

    stream - int 배열로 반환

    return answer.stream().mapToInt(Integer::intValue).toArray();

    스프링 데이터 JPA

    스프링 데이터에서 sql 관련한 여러 가지 기능들을 interface로 제공해준다.

    자주 사용하는 메서드(CRUD)는 이미 구현되어있기 때문에 새로운 interface repository를 생성해서 extends로 상속받아서 사용할 수 있다.

    extends JpaRepository<객체, PK Type>

    추가적인 구현이 필요할 경우에는 스프링 데이터 규칙에 따라 메서드를 생성하면 된다. (findBy...)

     

    동적 쿼리 구현이 미흡하기 때문에 추후 Querydsl에서 보완할 수 있다.

    많은 조건으로 인해 메서드 명이 복잡해질 경우 @Query를 통해 sql문을 직접 실행할 수 있다.

    @Param을 통해 파라미터를 받아야 한다.

     

    폴더 구조 분석

    1. ItemRepository(interface) <- JpaItemRepository(구현체) - 여기서 SpringDataJpaItemRepository를 DI 받음.

    2. JpaRepository(interface) <- SpringDataJpaItemRepository(interface)

    정리: ItemRepository는 근본적으로 SpringDataJpaItemRepository에 있는 메서드들을 구현체로 사용한다.

    * interface를 DI 받으면 OCP, DIP 원칙을 지킬 수 있다.

     

    OCP: 개방-폐쇄 원칙. 확장에는 열려있고 수정에는 닫혀있어야 한다.

    DIP: 의존 역전 원칙. 구현체에 의존하지 않고 인터페이스에 의존한다. 소프트웨어의 유연성과 유지보수성을 향상시킨다.

     


    Querydsl

    d: 도메인

    s: 특화

    l: 언어

     

    JPA, sql 등을 위해 type-safe Query Type을 생성해준다.

    APT: Annotation Processing tool 을 통해 query를 위한 새로운 entity를 생성한다.

    querydsl -> jpql -> sql 생성

     

    * EnntityManager, JPAQueryFactory를 필요로 한다.

    * 동적 쿼리를 가독성있게 다룰 수 있다.

    * 쿼리 문장에 오타가 있으면 컴파일 시점에 오류를 막을 수 있다.

    BooleanBuilder builder = new BooleanBuilder();
    if (StringUtils.hasText(itemName)) {
    	builder.and(item.itemName.like("%" + itemName + "%"));
    }
    if (maxPrice != null) {
    	builder.and(item.price.loe(maxPrice)); //Less than Or Equal to
    }
    
    query.select(QItem.item)
    	.from(QItem.item)
        .where(builder)
        .fetch();
    private BooleanExpression likeItemName(String itemName) {
        if (StringUtils.hasText(itemName)) {
            return item.itemName.like("%" + itemName + "%");
        }
        return null;
    }
    
    private BooleanExpression maxPrice(Integer maxPrice) {
        if (maxPrice != null) {
            return item.price.loe(maxPrice); //Less than Or Equal to
        }
        return null;
    }
    
    query.select(QItem.item)
    	.from(QItem.item)
    	.where(likeItemName(itemName), maxPrice(maxPrice))
        .fetch();

    트랜잭션 적용

    트랜잭션 프록시가 동작되고 트랜잭션 프록시를 스프링 빈으로 등록한다.

    @Transactional 이 있으면 트랜잭션 적용 대상이므로, true가 반환 값이다.

    TransactionSynchronizationManager는 쓰레드에 트랜잭션이 적용되어 있는지 확인할 수 있는 기능이다.

    TransactionSynchronizationManager.isActualTransactionActive();

     

    스프링에서 우선순위는 항상 더 구체적인 경우에 우선 순위를 가진다.

    @Transactional 설정 중, readOnly를 false/true를 class/method 단위에서 하는 지에 따라 다르게 적용된다.

     

    주의사항

    @Transactional을 사용하면 스프링에 트랜잭션 AOP가 설정된다.

    트랜잭션 AOP는 프록시 방식의 AOP를 사용한다. (public만 적용 가능)

     

    AOP 적용 시, 스프링은 프록시 객체를 빈으로 등록하기 때문에 실제 객체가 호출될 일이 일반적으로는 발생하지 않지만

    대상 객체의 내부에서 메서드 호출이 발생하면 프록시를 거치지 않고 직접 호출하는 문제가 발생한다.

    -> 내부 호출(this)의 문제

    별도의 클래스로 분리해서 외부 호출로 내부 호출을 피할 수 있다.

     

    @PostConstruct로 초기화를 하고 @Transactional을 적용하려고 할 때도 트랜잭션 적용이 안된다.

    (@PostConstruct: 의존성 주입이 완료된 후 초기화 작업을 실행할 )

    초기화 후 AOP가 적용된다.

    -> 초기화 문제

    스프링이 모두 준비된 상태 이후 트랜잭션이 적용되도록 한다.

    @EventListener(ApplicationReadyEvent.class)

     

    옵션

    @Transactional을 사용할 때, 체크 예외는 커밋하고 언체크 예외는 롤백하는 것이 기본적이다.

    체크 예외도 롤백하고 싶을 때 사용하는 옵션

    @Transactional(rollbackFor = Exception.class) //하위 예외도 적용됨

     

    728x90
    반응형

    'Blog > TIL' 카테고리의 다른 글

    [240526] API 개발하기  (0) 2024.05.26
    [240524] 수학 지식을 넓히자  (0) 2024.05.24
    [240522] 드디어 JPA를 접하다  (0) 2024.05.22
    [240521] JdbcTemplate 파헤쳐보기  (0) 2024.05.21
    [240520] 암기하지말고 이해하기  (0) 2024.05.20

    댓글