Загружаем каталог…
Загружаем каталог…
이번주에는 3주차에 작성했던 코드를 ORM을 이용해서 업드레이드 하는 실습을 진행했습니다. 1. 핵심 키워드 1-1. ORM ORM(Object-Relational Mapping)은 객체와 관계형 데이터베이스의 테이블을 연결해 주는 기술입니다. 개발자는 데이터베이스의 테이블을 Java 객체인 Entity로 표현하고, Repository를 통해 데이터를 조회하거나 저장할 수 있습니다. ORM을 사용하면 반복적인 CRUD 작업에서 SQL을 직접 작성하는 코드를 줄일 수 있습니다. 하지만 ORM을 사용하더라도 내부적으로는 SQL이 실행되기 때문에 SQL과 데이터베이스에 대한 이해가 필요합니다. 1-2. JPA와 Hibernate JPA(Java Persistence API)는 Java에서 ORM을 사용하기 위한 표준 명세입니다. Hibernate는 JPA의 표준을 실제로 구현한 대표적인 ORM 구현체입니다. 즉, JPA가 ORM을 사용하기 위한 규칙이라면 Hibernate는 그 규칙을 실제 코드로 동작하게 만들어 주는 구현체입니다. 1-3. Entity Entity는 데이터베이스의 테이블을 Java 클래스로 표현한 객체입니다. @Entity를 사용하면 해당 클래스가 JPA에서 관리하는 Entity임을 나타냅니다. @Id는 테이블의 기본 키를 나타내고, @Column을 사용하면 Java 필드와 데이터베이스의 컬럼을 연결할 수 있습니다. 예를 들어 book 테이블은 Book Entity로, category 테이블은 Category Entity로 표현할 수 있습니다. 1-4. Entity 관계 매핑 Entity 사이의 데이터베이스 관계를 Java 객체의 관계로 표현하는 것을 관계 매핑이라고 합니다. Book과 Category처럼 여러 개의 Book이 하나의 Category에 속하는 경우 @ManyToOne을 사용하여 다대일 관계를 표현할 수 있습니다. @JoinColumn은 관계를 연결하는 데이터베이스의 외래 키 컬럼을 지정합니다. 1-5. Persistence Context Persistence Context(영속성 컨텍스트)는 JPA가 Entity를 관리하는 공간입니다. Entity를 저장하거나 조회하면 JPA가 해당 Entity를 Persistence Context에서 관리하고, 변경 사항을 추적할 수 있습니다. 트랜잭션이 커밋되기 전까지 SQL 실행이 지연될 수 있으며, flush 시점에 변경 내용이 데이터베이스에 반영됩니다. 1-6. Repository Repository는 데이터베이스에 접근하는 역할을 담당하는 객체입니다. Spring Data JPA에서는 JpaRepository를 상속하면 기본적인 조회, 저장, 수정, 삭제 기능을 사용할 수 있습니다. 또한 메서드 이름을 이용하여 원하는 조건의 조회 기능을 만들 수 있습니다. 예를 들어 findAllByOrderByBookIdDesc()는 모든 Book을 bookId 기준 내림차순으로 조회합니다. 1-7. DTO DTO(Data Transfer Object)는 API를 통해 데이터를 주고받기 위한 객체입니다. Entity를 API에 그대로 사용하지 않고 DTO를 사용하면 데이터베이스 구조와 API의 데이터 형식을 분리할 수 있습니다. 요청 데이터를 받는 Request DTO와 응답 데이터를 전달하는 Response DTO를 별도로 만들 수 있습니다. 1-8. Validation Validation은 API로 들어오는 요청 데이터가 올바른 형식인지 확인하는 기능입니다. @Valid를 사용하면 DTO에 설정한 검증 조건을 요청 데이터에 적용할 수 있습니다. @NotNull은 값이 null인지 확인하고, @NotBlank는 문자열이 비어 있거나 공백인지 확인하며, @Size는 문자열 등의 크기를 제한할 때 사용합니다. 1-9. N+1 Query N+1 문제는 연관된 Entity를 조회하는 과정에서 예상보다 많은 SQL 쿼리가 실행되는 문제입니다. 예를 들어 게시글 10개를 한 번 조회한 후 각 게시글의 댓글을 조회하면서 10번의 추가 쿼리가 발생하면 총 11번의 쿼리가 실행됩니다. JOIN FETCH나 @BatchSize 등을 사용하여 불필요한 추가 쿼리를 줄일 수 있습니다. 1-10. Migration Migration은 데이터베이스의 테이블이나 컬럼 등의 구조 변경을 버전별로 관리하는 방법입니다. Entity의 변경 내용을 운영 데이터베이스에 자동으로 반영하는 방식은 예상하지 못한 스키마 변경이나 데이터 손실이 발생할 수 있기 때문에 주의해야 합니다. 운영 환경에서는 Flyway나 Liquibase와 같은 Migration 도구를 사용하여 스키마 변경을 명시적으로 관리할 수 있습니다. 2. 실습 2-1. 테이블을 Entity로 변환 기존 데이터베이스의 book과 category 테이블을 JPA에서 사용할 수 있도록 Entity 클래스로 변환했습니다. @Entity @Table(name = "category") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Category { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "category_id") private Long categoryId; @Column(nullable = false) private String name; } @Entity를 사용하여 Category 클래스를 JPA가 관리하는 Entity로 지정했습니다. @Table을 통해 실제 데이터베이스의 category 테이블과 연결하고, @Id와 @GeneratedValue를 사용하여 기본 키를 매핑했습니다. 다음으로 book 테이블을 Book Entity로 만들었습니다. @Entity @Table(name = "book") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "book_id") private Long bookId; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "category_id", nullable = false) private Category category; @Column(nullable = false, length = 100) private String title; @Column(columnDefinition = "TEXT") private String description; @Column(name = "is_available", nullable = false) private Boolean isAvailable = true; } 기존 book 테이블의 category_id가 category 테이블을 참조하고 있기 때문에 @ManyToOne과 @JoinColumn을 사용했습니다. 이를 통해 여러 개의 Book이 하나의 Category에 속하는 다대일 관계를 Entity에서도 표현했습니다. 2-2. ORM 연결과 Repository 등록 JPA를 사용하기 위해 build.gradle에 Spring Data JPA 의존성을 추가했습니다. implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 기존 3주차에서는 JdbcTemplate을 사용하여 직접 SQL을 작성했지만, 이번에는 Spring Data JPA의 JpaRepository를 사용했습니다. public interface BookRepository extends JpaRepository<Book, Long> { List<Book> findAllByOrderByBookIdDesc(); } JpaRepository<Book, Long>을 상속하면 Book Entity에 대한 기본적인 조회, 저장, 수정, 삭제 기능을 사용할 수 있습니다. 또한 findAllByOrderByBookIdDesc()와 같이 메서드 이름을 작성하면 별도의 SQL을 직접 작성하지 않아도 bookId를 기준으로 내림차순 조회할 수 있습니다. 2-3. DTO로 API의 약속 만들기 Entity를 API의 요청과 응답에 그대로 사용하지 않고 DTO를 만들었습니다. 먼저 도서를 등록할 때 사용할 요청 DTO를 작성했습니다. public record CreateBookRequest( @NotNull Long categoryId, @NotBlank @Size(max = 100) String title, String description ) { } categoryId는 반드시 입력되어야 하고, title은 비어 있으면 안 되도록 검증 조건을 추가했습니다. 다음으로 GET 요청에서 사용할 응답 DTO를 작성했습니다. public record BookResponse( Long bookId, String title, String description, String categoryName, Boolean isAvailable ) { } API에서 필요한 값만 응답하도록 BookResponse를 만들었기 때문에 Entity의 전체 구조와 API 응답 형식을 분리할 수 있었습니다. 2-4. GET /books 만들기 Entity, Repository, DTO를 만든 후 실제 GET API를 구현했습니다. 먼저 Service에서 Repository를 통해 도서를 조회하고 BookResponse로 변환했습니다. @Transactional(readOnly = true) public List<BookResponse> getBooks() { return bookRepository.findAllByOrderByBookIdDesc() .stream() .map(BookResponse::from) .toList(); } findAllByOrderByBookIdDesc()를 통해 도서를 최신순으로 조회하고, 조회된 Book Entity를 BookResponse로 변환했습니다. 그다음 Controller에서 GET 요청을 받을 수 있도록 작성했습니다. @GetMapping public List<BookResponse> getBooks() { return bookService.getBooks(); } 이렇게 하면 다음과 같은 흐름으로 요청이 처리됩니다. GET /books ↓ BookController ↓ BookService ↓ BookRepository ↓ Database ↓ BookResponse 마지막으로 Postman에서 GET http://localhost:8080/books 를 요청하여 도서 ID, 제목, 설명, 카테고리 이름, 대여 가능 여부가 최신순으로 반환되는 것을 확인했습니다. 마무리 이번 주차 워크북에서는 3주차에 작성했던 기존 코드를 발전시키는 과정이라 과제 자체는 크게 어렵지 않았지만, DTO와 Entity 같은 새로운 개념과 파일들이 추가되면서 각각의 파일이 어떤 역할을 하고 서로 어떻게 연결되는지 조금 헷갈렸습니다. 특히 DB 테이블을 Entity로 변환할 때 어노테이션을 사용해 컬럼 이름, null 가능 여부, 기본키, 관계 등을 하나씩 설정해야 해서 확인해야 할 부분이 많아 어려움을 조금 느꼈습니다. 단순히 테이블을 코드로 옮기는 것뿐만 아니라 데이터베이스와 객체의 관계까지 생각해야 한다는 점에서 ORM의 특징을 조금 더 이해할 수 있었습니다. 반면 Repository를 사용하면서 편리함을 크게 느꼈습니다. 특히 findAllByOrderByBookIdDesc()처럼 메서드 이름만으로 원하는 정렬 조건의 데이터를 조회할 수 있다는 점이 인상적이었습니다. 직접 SQL을 작성하지 않아도 필요한 데이터를 조회할 수 있다는 점에서 ORM을 사용하는 이유를 체감할 수 있었습니다. 아직 Entity, DTO, Repository, Controller 등의 관계가 완전히 익숙하지는 않지만, 각각의 역할을 구분하면서 코드를 작성해보니 앞으로 API 구조를 이해하는 데 도움이 될 것 같습니다.
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
[UMC 블로그챌린지] PE-Mobile 파트 4주차_1. 이번주에는 3주차에 작성했던 코드를 ORM을 이용해서 업드레이드 하는 실습을 진행했습니다. 1. 핵심 키워드 1-1. ORM ORM(Object-Relational Mapping)은 객체와 관계형 데이터베이스의 테이블을 연결해 주는 기술입니다. 개발자는 데이터베이스의 테이블을 Java 객체인 Entity로 표현하고, Repository를 통해 데이터를 조회하거나 저장할 수 있습니다. ORM을 사용하면 반복적인 CRUD 작업에서 SQL을 직접 작성하는 코드를 줄일 수 있습니다. 하지만 ORM을 사용하더라도 내부적으로는 SQL이 실행되기 때문에 SQL과 데이터베이스에 대한 이해가 필요합니다. 1-2. JPA와 Hibernate JPA(Java…
Открыть источник