Spring Data JPA: 효과적인 데이터베이스 연동을 위한 필수 도구

Spring Data JPA는 데이터베이스와 상호작용하는 애플리케이션을 더 쉽고 효율적으로 개발할 수 있게 해주는 강력한 프레임워크입니다.

1️⃣ JPA란?

Java Persistence API의 약자인 JPA는 자바 객체와 데이터베이스 간의 매핑을 처리하기 위한 ORM(Object Relational Mapping) 기술입니다.

특징

  1. 객체지향 프로그래밍 지원:
    JPA는 자바의 객체지향 구조를 유지하면서 데이터를 데이터베이스에 저장하거나 읽어올 수 있습니다.
  2. 표준 인터페이스 제공:
    Hibernate, EclipseLink와 같은 ORM 프레임워크들이 JPA 표준을 구현하여 사용됩니다.
  3. 생산성 향상:
    SQL을 직접 작성하지 않고도 데이터베이스 작업이 가능하므로 개발 속도가 빨라집니다.
  4. 영속성 컨텍스트:
    JPA는 엔티티의 상태를 관리하여 데이터베이스와 동기화합니다.

2️⃣ Spring Data JPA란?

Spring Data JPA는 JPA를 더 편리하게 사용할 수 있도록 도와주는 Spring 모듈입니다.

  • JPA의 반복적인 작업을 줄이고, 데이터 접근 계층을 간단히 작성할 수 있도록 지원합니다.
  • SQL 작성 없이 메서드 이름만으로 쿼리를 실행하는 기능을 제공합니다.

3️⃣ Spring Data JPA to DB 호출 구조

Spring Data JPA를 사용하면 애플리케이션에서 데이터베이스까지의 흐름이 다음과 같이 단계적으로 진행됩니다.

  1. Spring Data JPA
  • 요청: 사용자의 요청이 ServiceRepository 계층을 통해 들어옵니다.
  • 이 요청은 JPA를 사용해 데이터를 조회하거나 변경하려는 작업입니다.
  1. JPA
  • 변환/위임: JPA는 요청받은 작업을 객체를 기반으로 처리하고, Hibernate와 같은 구현체에게 위임합니다.
  1. Hibernate
  • SQL 실행 요청: Hibernate는 JPA에서 받은 작업을 기반으로 적절한 SQL 쿼리를 생성하고, JDBC를 통해 데이터베이스와 연결합니다.
  1. JDBC
  • DB 연결/쿼리 전달: JDBC는 데이터베이스 드라이버(DB Driver)를 통해 SQL 쿼리를 DBMS로 전달합니다.
  1. DB Driver → DBMS
  • 실제 쿼리 실행: DBMS에서 SQL 쿼리를 실행하고 결과를 반환합니다.
  1. 결과 반환
  • DBMS → DB Driver → JDBC: 실행된 쿼리의 결과가 JDBC를 통해 다시 Hibernate로 전달됩니다.
  • Hibernate → JPA: Hibernate는 결과를 엔티티(Entity)로 변환합니다.
  • JPA → Spring Data JPA: 최종적으로 JPA를 통해 결과가 Spring Data JPA로 반환됩니다.

정리된 호출 흐름

Spring Data JPA → JPA → Hibernate → JDBC → DB Driver → DBMS  
  ←               ←         ←        ←        ←          ←  
최종 결과 반환  

설명

  • 각 계층이 맡은 역할에 따라 요청이 전달되고, 결과는 반대로 흐르며 반환됩니다.
  • JPA가 직접 SQL 쿼리를 작성하지 않으며, Hibernate가 대신 SQL을 생성하고 실행을 위임합니다.
  • 결과는 객체(Entity) 형태로 변환되어 비즈니스 로직에서 사용됩니다.

Spring Data Jpa to DB 까지의 호출구조

4️⃣ Spring Data JPA의 자주 사용하는 어노테이션

1. @Entity

  • 데이터베이스 테이블과 매핑되는 클래스임을 명시.

    @Entity
    public class User {
       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       private Long id;
    
       @Column(nullable = false)
       private String name;
    }

2. @Id / @GeneratedValue

  • @Id: 기본 키(Primary Key)를 지정.
  • @GeneratedValue: 키 생성 전략 설정.
    • IDENTITY: 데이터베이스가 자동 생성.
    • SEQUENCE: JPA가 별도의 시퀀스를 사용해 생성.

3. @Column

  • 데이터베이스 컬럼 매핑 및 제약 조건 설정.
  • 예: nullable, unique, length 등.
    @Column(nullable = false, unique = true, length = 100)
    private String email;

4. @Query

  • 복잡한 SQL 쿼리를 작성할 때 사용.
    @Query("SELECT u FROM User u WHERE u.name = :name")
    User findByName(@Param("name") String name);

5. @Transactional

  • 메서드 또는 클래스에 트랜잭션 범위 설정.
    @Transactional
    public void updateUser(Long id, String name) {
       User user = userRepository.findById(id).orElseThrow();
       user.setName(name);
    }

5️⃣ 코드 예제: 기본 CRUD Repository 구현

1. Entity 생성

@Entity
public class User {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;

   @Column(nullable = false)
   private String name;

   @Column(nullable = false, unique = true)
   private String email;

   // Getter, Setter
}

2. Repository 작성

public interface UserRepository extends JpaRepository<User, Long> {
   List<User> findByName(String name); // 메서드 이름만으로 쿼리 실행
}

3. Service 작성

@Service
@RequiredArgsConstructor
public class UserService {
   private final UserRepository userRepository;

   public User createUser(String name, String email) {
       User user = new User();
       user.setName(name);
       user.setEmail(email);
       return userRepository.save(user);
   }

   public List<User> getUsersByName(String name) {
       return userRepository.findByName(name);
   }
}

4. Controller 작성

@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {
   private final UserService userService;

   @PostMapping
   public ResponseEntity<User> createUser(@RequestBody User user) {
       return ResponseEntity.ok(userService.createUser(user.getName(), user.getEmail()));
   }

   @GetMapping
   public ResponseEntity<List<User>> getUsersByName(@RequestParam String name) {
       return ResponseEntity.ok(userService.getUsersByName(name));
   }
}

6️⃣ 작성 시 주의사항

  1. 엔티티 설계 시 양방향 매핑에 주의:
    양방향 관계에서는 무한 루프를 방지하기 위해 @JsonIgnore 또는 DTO 사용 필요.

  2. N+1 문제 방지:
    연관 데이터를 조회할 때 필요 이상의 쿼리가 발생하지 않도록 페치 조인 또는 @EntityGraph를 사용.

    @EntityGraph(attributePaths = "orders")
    List<User> findAllWithOrders();
  3. 트랜잭션 관리:
    데이터의 일관성을 보장하기 위해 서비스 계층에서 트랜잭션 설정 권장.

  4. SQL 최적화:
    복잡한 쿼리는 @Query나 QueryDSL을 활용하여 작성.

7️⃣ Spring Data JPA의 장점

  • 생산성: CRUD 메서드 자동 생성으로 반복 작업 감소.
  • 유연성: 다양한 방식으로 쿼리를 작성할 수 있음.
  • 확장성: QueryDSL, 스펙(Specification) 등 다양한 확장 도구와 호환 가능.

profile
다 먹어버릴거야!

0개의 댓글