213 lines
7.4 KiB
Markdown
213 lines
7.4 KiB
Markdown
# **데이터 처리와 JPA**
|
|
|
|
웹 애플리케이션에서 **데이터 처리(Data Processing)**는 필수적인 요소이며, 이를 효율적으로 다루기 위해 ORM 프레임워크인 **JPA (Java Persistence API)**가 널리 사용됩니다.
|
|
이번 글에서는 **JPA의 기본 개념, 주요 기능, 실무 적용 방법**을 살펴보겠습니다.
|
|
|
|
---
|
|
|
|
## **1. 데이터 처리란?**
|
|
|
|
데이터 처리는 애플리케이션이 데이터를 **생성(Create), 읽기(Read), 수정(Update), 삭제(Delete)**하는 과정(**CRUD**)을 의미합니다.
|
|
Spring Boot에서는 **JPA와 Spring Data JPA**를 활용하여 효율적인 데이터 처리를 구현할 수 있습니다.
|
|
|
|
**📌 전통적인 JDBC 방식과 JPA 방식 비교**
|
|
|
|
| 방식 | 특징 | 코드 복잡도 | 유지보수성 |
|
|
|------|------|------------|------------|
|
|
| **JDBC (기본 SQL 사용)** | SQL 쿼리를 직접 작성 | 높음 | 낮음 |
|
|
| **JPA (ORM 방식)** | 객체 중심의 데이터 처리 | 낮음 | 높음 |
|
|
|
|
---
|
|
|
|
## **2. JPA란?**
|
|
|
|
**JPA (Java Persistence API)**는 객체지향적인 방식으로 데이터베이스를 다룰 수 있도록 도와주는 **ORM(Object-Relational Mapping) 기술**입니다.
|
|
JPA를 사용하면 SQL을 직접 작성하지 않고, **엔티티(Entity) 객체를 이용하여 데이터베이스를 조작**할 수 있습니다.
|
|
|
|
### **📌 JPA의 핵심 개념**
|
|
1. **엔티티(Entity):** 데이터베이스 테이블과 매핑되는 클래스
|
|
2. **리포지토리(Repository):** 데이터 저장 및 조회를 담당하는 계층
|
|
3. **트랜잭션(Transaction):** 데이터 변경 작업을 하나의 단위로 처리
|
|
4. **JPQL(Java Persistence Query Language):** 객체를 대상으로 하는 쿼리
|
|
|
|
---
|
|
|
|
## **3. JPA 실무 적용**
|
|
|
|
### **📌 1) Entity (데이터 모델 정의)**
|
|
JPA에서는 `@Entity` 어노테이션을 사용하여 **클래스를 데이터베이스 테이블과 매핑**합니다.
|
|
|
|
```java
|
|
import jakarta.persistence.*;
|
|
|
|
@Entity // User 엔티티는 DB의 users 테이블과 매핑됨
|
|
@Table(name = "users")
|
|
public class User {
|
|
|
|
@Id
|
|
@GeneratedValue(strategy = GenerationType.IDENTITY) // 자동 증가 ID
|
|
private Long id;
|
|
|
|
@Column(nullable = false) // name 컬럼은 null을 허용하지 않음
|
|
private String name;
|
|
|
|
@Column(nullable = false)
|
|
private int age;
|
|
|
|
public User() {}
|
|
|
|
public User(String name, int age) {
|
|
this.name = name;
|
|
this.age = age;
|
|
}
|
|
|
|
// Getter & Setter 생략
|
|
}
|
|
```
|
|
✔ **`@Entity`**: 해당 클래스가 데이터베이스 테이블과 연결됨
|
|
✔ **`@Table(name = "users")`**: 테이블명을 `users`로 지정
|
|
✔ **`@Id`**: 기본 키(Primary Key) 설정
|
|
✔ **`@GeneratedValue(strategy = GenerationType.IDENTITY)`**: 자동 증가(AUTO_INCREMENT) 설정
|
|
✔ **`@Column(nullable = false)`**: `null`을 허용하지 않도록 설정
|
|
|
|
---
|
|
|
|
### **📌 2) Repository (데이터 접근 계층)**
|
|
JPA에서는 **Spring Data JPA**의 `JpaRepository` 인터페이스를 사용하면, 기본적인 CRUD 기능을 자동으로 구현할 수 있습니다.
|
|
|
|
```java
|
|
import org.springframework.data.jpa.repository.JpaRepository;
|
|
import org.springframework.stereotype.Repository;
|
|
|
|
@Repository
|
|
public interface UserRepository extends JpaRepository<User, Long> {
|
|
// 기본 CRUD 기능 제공
|
|
}
|
|
```
|
|
✔ **`JpaRepository<User, Long>`**: `User` 엔티티를 관리하며, 기본 키 타입은 `Long`
|
|
✔ `findById(id)`, `save(entity)`, `deleteById(id)` 등 기본적인 데이터 처리 메서드 제공
|
|
|
|
---
|
|
|
|
### **📌 3) Service (비즈니스 로직 계층)**
|
|
데이터 처리 로직을 서비스 계층에서 구현하여 컨트롤러와 분리합니다.
|
|
|
|
```java
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.util.List;
|
|
|
|
@Service
|
|
public class UserService {
|
|
|
|
@Autowired
|
|
private UserRepository userRepository;
|
|
|
|
@Transactional
|
|
public User createUser(String name, int age) {
|
|
if (age < 0) {
|
|
throw new IllegalArgumentException("나이는 0 이상이어야 합니다.");
|
|
}
|
|
return userRepository.save(new User(name, age));
|
|
}
|
|
|
|
public List<User> getAllUsers() {
|
|
return userRepository.findAll();
|
|
}
|
|
}
|
|
```
|
|
✔ **서비스 계층을 사용하여 비즈니스 로직을 분리**
|
|
✔ **`@Transactional`을 사용하여 트랜잭션 관리**
|
|
|
|
---
|
|
|
|
### **📌 4) Controller (요청 처리 계층)**
|
|
사용자의 요청을 받아 서비스 계층을 호출하고 응답을 반환합니다.
|
|
|
|
```java
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.http.ResponseEntity;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
import java.util.List;
|
|
|
|
@RestController
|
|
@RequestMapping("/users")
|
|
public class UserController {
|
|
|
|
@Autowired
|
|
private UserService userService;
|
|
|
|
@PostMapping
|
|
public ResponseEntity<User> createUser(@RequestParam String name, @RequestParam int age) {
|
|
return ResponseEntity.ok(userService.createUser(name, age));
|
|
}
|
|
|
|
@GetMapping
|
|
public ResponseEntity<List<User>> getAllUsers() {
|
|
return ResponseEntity.ok(userService.getAllUsers());
|
|
}
|
|
}
|
|
```
|
|
✔ **`@RestController`**: JSON 형식으로 데이터를 반환하는 컨트롤러
|
|
✔ **`@RequestMapping("/users")`**: `/users` 경로의 API를 처리
|
|
✔ **`@PostMapping`**: 새로운 사용자 생성
|
|
✔ **`@GetMapping`**: 모든 사용자 조회
|
|
|
|
---
|
|
|
|
## **4. JPA에서 데이터 조회 (JPQL & Native Query)**
|
|
|
|
### **📌 1) JPQL (Java Persistence Query Language)**
|
|
JPA에서는 SQL 대신 **JPQL**을 사용하여 객체 중심의 쿼리를 작성할 수 있습니다.
|
|
|
|
```java
|
|
import org.springframework.data.jpa.repository.Query;
|
|
import org.springframework.data.repository.query.Param;
|
|
import java.util.List;
|
|
|
|
public interface UserRepository extends JpaRepository<User, Long> {
|
|
|
|
// 이름으로 사용자 찾기
|
|
@Query("SELECT u FROM User u WHERE u.name = :name")
|
|
List<User> findByName(@Param("name") String name);
|
|
}
|
|
```
|
|
✔ SQL과 유사하지만, **테이블명이 아니라 엔티티 클래스명을 사용**
|
|
|
|
---
|
|
|
|
### **📌 2) Native Query (SQL 직접 사용)**
|
|
기본 SQL 쿼리를 직접 사용할 수도 있습니다.
|
|
|
|
```java
|
|
@Query(value = "SELECT * FROM users WHERE age >= :age", nativeQuery = true)
|
|
List<User> findUsersByAge(@Param("age") int age);
|
|
```
|
|
✔ 복잡한 SQL 쿼리를 그대로 활용 가능
|
|
|
|
---
|
|
|
|
## **5. JPA의 장점과 단점**
|
|
|
|
### **📌 JPA의 장점**
|
|
✔ **SQL을 직접 작성할 필요 없음** → 생산성 증가
|
|
✔ **객체지향적인 데이터 처리 가능** → 코드의 가독성과 유지보수성 향상
|
|
✔ **트랜잭션 관리가 용이함**
|
|
✔ **캐싱 및 성능 최적화 기능 제공**
|
|
|
|
### **📌 JPA의 단점**
|
|
❌ 초기 학습 비용이 존재
|
|
❌ 복잡한 SQL 튜닝이 필요한 경우 SQL보다 불리할 수 있음
|
|
❌ 데이터베이스 변경 시, 마이그레이션이 필요
|
|
|
|
---
|
|
|
|
## **6. 정리**
|
|
✔ **JPA는 객체지향 방식으로 데이터를 처리하는 ORM 기술**
|
|
✔ **Entity, Repository, Service, Controller 구조로 데이터 처리를 설계**
|
|
✔ **JPQL 및 Native Query를 활용하여 데이터 조회 가능**
|
|
✔ **트랜잭션을 활용하여 데이터 일관성을 유지**
|
|
|
|
JPA를 활용하면 **효율적인 데이터 처리와 유지보수성 높은 애플리케이션을 만들 수 있습니다!** |