TIL - 20250809

juni·2025년 8월 9일

TIL

목록 보기
89/316

0809 QueryDSL 심화 및 데이터베이스 트랜잭션/제어


✅ QueryDSL: 서브쿼리 및 동적 쿼리

  • QueryDSL은 복잡한 SQL 쿼리를 타입에 안전한(Type-Safe) Java 코드로 작성하게 해주는 프레임워크입니다. 이를 통해 컴파일 시점에 오류를 잡고, 가독성 높은 코드를 유지할 수 있습니다.

➕ 서브쿼리 (JPAExpressions)

  • JPAExpressions 유틸리티 클래스를 사용하여 SELECT, WHERE, HAVING 절 등에서 서브쿼리를 작성할 수 있습니다.

  • 주요 사용 사례:

    1. 특정 그룹 평균 나이보다 많은 아이돌 조회 (WHERE 절):

      // 르세라핌 평균 나이보다 많은 아이돌 조회
      List<Idol> result = factory.selectFrom(idol)
          .where(idol.age.gt(
              JPAExpressions.select(idol.age.avg()).from(idol)
                            .where(idol.group.groupName.eq("르세라핌"))
          )).fetch();
    2. 그룹이 존재하지 않는 아이돌 조회 (NOT EXISTS):

      List<Idol> result = factory.selectFrom(idol)
          .where(JPAExpressions.select(group.id)
              .from(group)
              .where(group.id.eq(idol.group.id))
              .notExists()
          ).fetch();
    3. 특정 연도에 앨범을 2개 이상 발매한 그룹 조회 (IN + HAVING):

      // 2022년에 앨범을 2개 이상 발매한 그룹 ID 조회 서브쿼리
      JPQLQuery<Long> subQuery = JPAExpressions
          .select(subAlbum.group.id).from(subAlbum)
          .where(subAlbum.releaseYear.eq(2022))
          .groupBy(subAlbum.group.id)
          .having(subAlbum.count().goe(2L));
      
      // 메인 쿼리에서 해당 그룹들 조회
      List<Group> result = factory.selectFrom(group)
          .where(group.id.in(subQuery))
          .fetch();

➕ 동적 쿼리 (BooleanBuilder & OrderSpecifier)

  • 사용자의 검색 조건이나 정렬 기준에 따라 쿼리가 동적으로 변경되어야 할 때 사용합니다.
  1. 동적 조건 (BooleanBuilder):

    • BooleanBuilder 객체에 if 문을 사용하여 조건이 존재할 경우에만 .and() 메서드로 쿼리 조건을 추가합니다.
    BooleanBuilder builder = new BooleanBuilder();
    if (name != null) builder.and(idol.idolName.eq(name));
    if (minAge != null) builder.and(idol.age.goe(minAge));
    
    List<Idol> result = factory.selectFrom(idol).where(builder).fetch();
  2. 동적 정렬 (OrderSpecifier):

    • switch 문이나 if 문을 사용하여 정렬 기준(sortBy)과 방향(ascending)에 따라 적절한 OrderSpecifier를 생성합니다.
    OrderSpecifier<?> specifier = switch (sortBy) {
        case "age" -> ascending ? idol.age.asc() : idol.age.desc();
        case "idolName" -> ascending ? idol.idolName.asc() : idol.idolName.desc();
        default -> idol.id.asc(); // 기본 정렬
    };
    
    List<Idol> result = factory.selectFrom(idol).orderBy(specifier).fetch();

✅ 트랜잭션(Transaction)과 DCL

➕ 트랜잭션(Transaction)과 ACID 원칙

  • 트랜잭션: 데이터베이스의 상태를 변화시키는 하나의 논리적 작업 단위입니다. All or Nothing 원칙에 따라 작업 내의 모든 연산이 성공하거나, 하나라도 실패하면 모든 변경 사항이 되돌려져야(롤백) 합니다.

  • 주요 명령어:

    • COMMIT: 모든 작업을 최종적으로 데이터베이스에 영구 저장합니다.
    • ROLLBACK: 작업 중 발생한 모든 변경 사항을 취소하고 트랜잭션 이전 상태로 되돌립니다.
    • SAVEPOINT: 트랜잭션 내에 중간 저장 지점을 만들어, 전체가 아닌 특정 지점까지만 롤백할 수 있게 합니다.
  • ACID (트랜잭션 4대 특성): 데이터베이스 트랜잭션의 안정성을 보장하는 4가지 성질입니다.

특성설명
원자성 (Atomicity)트랜잭션의 연산은 모두 반영되거나, 아니면 모두 반영되지 않아야 한다.
일관성 (Consistency)트랜잭션 실행 후에도 데이터베이스는 항상 일관된 상태를 유지해야 한다.
격리성 (Isolation)둘 이상의 트랜잭션이 동시에 실행될 때, 서로의 작업에 영향을 주지 않아야 한다.
지속성 (Durability)성공적으로 완료된(COMMIT된) 트랜잭션의 결과는 영구적으로 저장되어야 한다.

➕ DCL (데이터 제어어)과 ROLE

  • DCL (Data Control Language): 데이터베이스 객체에 대한 접근 권한을 부여(GRANT)하거나 회수(REVOKE)하는 명령어입니다.

  • 권한의 종류:

    • 시스템 권한: DB 접속(CREATE SESSION), 테이블 생성(CREATE TABLE) 등 시스템 차원의 권한.
    • 객체 권한: 특정 테이블에 대한 조회(SELECT), 수정(UPDATE) 등 특정 객체에 대한 권한.
  • ROLE: 여러 권한들을 하나로 묶어 관리하는 '권한 꾸러미'입니다. 사용자에게 직접 권한을 부여하는 대신, 직책(e.g., 개발자, 마케터)에 맞는 ROLE을 부여하여 권한 관리를 효율적이고 체계적으로 할 수 있습니다.

    -- 1. ROLE 생성
    CREATE ROLE DEV_ROLE;
    
    -- 2. ROLE에 권한들 부여
    GRANT CREATE SESSION, CREATE TABLE TO DEV_ROLE;
    GRANT SELECT, INSERT ON EMPLOYEES TO DEV_ROLE;
    
    -- 3. 사용자에게 ROLE 부여
    GRANT DEV_ROLE TO DEV01;

📌 요약

  • QueryDSL을 사용하면 JPAExpressions로 타입-세이프한 서브쿼리를, BooleanBuilderOrderSpecifier동적 쿼리 및 정렬을 효과적으로 구현할 수 있습니다.
  • 트랜잭션은 데이터의 무결성을 보장하는 논리적 작업 단위이며, ACID 원칙을 통해 안정성을 확보합니다. COMMITROLLBACK으로 제어됩니다.
  • DCL(GRANT, REVOKE)은 데이터 접근 권한을 제어하는 언어이며, 여러 권한을 묶은 ROLE을 활용하면 다수 사용자의 권한을 효율적으로 관리할 수 있습니다.

0개의 댓글