Persistence Framework는 애플리케이션이 데이터를 지속적으로 저장하고 관리하기 위해 사용하는 Spring의 소프트웨어 라이브러리입니다. 개발자가 데이터베이스와 쉽게 상호작용할 수 있도록 여러 기능을 제공합니다.
JDBC (Java Database Connectivity)는 자바 애플리케이션을 데이터베이스와 연결하는 SQL 쿼리를 실행하기 위한 표준 API입니다. SQL 쿼리를 직접 작성하면 그 결과를 자바 객체로 매핑할 수 있지만, 이 과정을 개발자가 직접 진행해야 합니다. 많은 보일러플레이트 코드를 반복해서 작성해야 하는 번거로움이 있습니다.
ORM은 객체와 관계형 데이터베이스를 연결하는 기술입니다. 자바 같은 객체 지향 프로그래밍 언어에서 사용하는 객체(클래스)와 데이터베이스의 테이블을 자동으로 매핑해줍니다. 이를 통해 개발자는 SQL문을 직접 작성하지 않고도 데이터베이스와 상호작용할 수 있습니다.
ORM이 하는 일을 이렇게 정리할 수 있습니다.
객체로 관리 테이블로 관리즉, 객체를 통해 데이터베이스를 조작할 수 있게 하는 기술을 말합니다.
JPA는 자바에서 ORM의 사용 방법을 표준화한 스펙입니다. JPA를 사용하면 ORM 프레임워크를 따를 수 있는 규칙을 제공받을 수 있습니다. 영속성 컨텍스트, 엔티티 매니저,트랜잭션 관리 등의 규칙을 제공합니다. JPA는 자체적으로 구현되지 않습니다. Hibernate와 같은 ORM 프레임워크가 이러한 JPA 스펙을 구현합니다.
MVC 패턴은 애플리케이션의 구조를 세 부분으로 나누어 설계하는 디자인 패턴입니다. JPA 스펙을 사용해 어플리케이션을 개발할 때 MVC 패턴을 적용해 설계할 수 있습니다.
JPA는 데이터베이스와 상호작용하면서 데이터를 관리할 수 있도록 도와주는 도구이기 때문에, Model, View, Controller 중 Model 계층에 사용됩니다. 예를 들어, JPA는 사용자 정보를 'User' 클래스와 같은 엔티티에 저장하고, CRUD 작업을 쉽게 처리하는 데이터 관리 기능을 제공합니다.
✅ 어노테이션: 자바 객체와 데이터베이스 테이블을 매핑하는데 사용합니다. @Entity, @Table, @Id, @Column 등의 어노테이션을 사용하여, 클래스와 필드가 데이터베이스 테이블과 컬럼에 매핑됨을 나타냅니다.
✅ 엔티티: 데이터베이스의 테이블에 매핑되는 자바 객체로, 엔티티 기능을 사용해 CRUD 작업을 쉽게 처리할 수 있습니다.
✅ DTO: 데이터를 전송하는 자바 객체로, 엔티티와 뷰 사이에서 데이터를 전달하는 역할을 합니다.
✅ Entity 클래스 정의
데이터베이스 테이블과 매핑되며, 각 필드가 테이블 칼럼에 해당합니다.
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class User {
@Id // 기본키 지정
@GeneratedValue(strategy = GenerationType.IDENTITY) // 데이터베이스 기본키 값을 MySQL 같은 데이터베이스에서 자동으로 생성하도록 지정
private Long id;
private String name;
private String email;
// lombok을 사용해 getter, setter, constructor 쉽게 추가 가능
}
✅ Repository 인터페이스 정의
Spring Data JPA가 제공하는 JPARepository를 상속받아 기본적인 CRUD 메소드와 커스텀 쿼리 메소드를 사용하게 해줍니다.
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByName(String name);
}
// 관리할 엔티티 클래스명 -> User
// 해당 엔티티의 기본키 타입 -> Long
// 커스텀 쿼리 메소드 -> findByName
// 'name'필드와 인자 값이 일치하는 모든 User 엔티티를 검색
// 메소드 이름을 기반으로 SQL 쿼리를 자동 생성
// 추후에 컨트롤러나 서비스 클래스에서 이 메소드를 호출하면 사용자 목록을 가져올 수 있다.
✅ Controller 클래스 정의
사용자가 웹브라우저를 통해 입력하는 내용을 서비스 계층에 전달합니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController // 모든 메소드의 응답을 JSON이나 XML로 변환
@RequestMapping("/users") // 모든 메소드가 사용하는 기본 경로 설정
public class UserController {
@Autowired // 아래 클래스의 객체가 필요하다고 선언 -> 이후 메소드에서 변수
private UserService userService;
// 1. 클라이언트가 JSON 형식으로 데이터를 보낼 때
// API 호출이나 프론트엔드 프레임워크와의 통신에 적합
@PostMapping // 필요하면 추가 경로 지정 ("/{new}")
public User createUser(@RequestBody UserDTO userDTO) { // 클라이언트가 JSON 데이터를 서버로 보내면 'UserDTO' 객체로 변환해서 사용하겠다는 뜻
User user = new User(); // 새 사용자 객체 생성
user.setId(userDTO.getId());
user.setName(userDTO.getName());
user.setEmail(userDTO.getEmail());
return userService.saveUser(user); // 결과 반환
}
💡 @Autowired 란?
Spring은 애플리케이션을 실행할 때 필요한 객체들을 미리 만들어서 관리하는데, 이러한 객체들을 '빈'이라고 부릅니다. 필요한 객체로 지정하기 위해서는 어노테이션을 해당 클래스에 붙여야 합니다.
@Component: 일반적인 스프링 빈
@Service: 서비스 계층을 나타내는 빈
@Repository: 데이터 접근 계층을 나타내는 빈
@Controller: 웹 컨트롤러를 나타내는 빈
Spring은 클래스에 붙은 어노테이션을 확인 후, 해당 클래스를 빈으로 생성해서 관리하게 됩니다. 즉, @Autowired를 사용한다는 것은 해당 타입의 '빈'을 자동으로 주입한다는 것을 의미합니다. 별도로 객체를 생성할 필요 없이, Spring이 이미 만들어 놓은 객체를 코드에서 필요한 곳에 자동으로 넣어줄 수 있습니다.
// 2. 클라이언트가 URL 파라미터로 데이터를 보낼 때
// 검색 필터링이나 간단한 폼 데이터 전송에 적합
@PostMapping
public User createUser(@RequestParam Long id, @RequestParam String name, @RequestParam String email) {
User user = new User(); // 새 사용자 객체 생성
user.setId(id);
user.setName(name);
user.setEmail(email);
return userService.saveUser(user); // 결과 반환
}
UserDTO는 User 엔티티와 비슷하지만, 사용 목적에 따라 다르게 구성할 수 있습니다.
public class UserDTO {
private Long id;
private String name;
private String email;
✅ Service 클래스 정의
비즈니스 로직을 처리하는 클래스로, Controller와 Repository 사이를 연결하며 데이터베이스와 상호작용합니다.
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 saveUser(User user) {
return userRepository.save(user);
}
데이터 변경 작업을 트랜잭션 내에서 안전하게 수행하기 위해서 @Transactional 어노테이션을 사용할 수 있습니다.
ORM (Object-Relational Mapping)
JPA (Java Persistence API)
Spring Data JPA