[개념 콕] 스프링 JPA란? <ORM, Hibernate, JPA>

내일배움캠프 수료생이 개발에 꼭 필요한 핵심 개념만 콕 집어 드립니다.
Jun 03, 2024
[개념 콕] 스프링 JPA란? <ORM, Hibernate, JPA>
✍🏼
개발을 시작하시는 여러분, 정보가 너무 많고 배워야 할 것도 산더미라 어디서부터 시작해야 할지 막막하신가요? 내일배움캠프 수료생들이 4개월 동안 배운 엄선된 핵심 개념을 직접 정리해서 알려 드립니다. 공부하다 막히거나 헷갈리는 개념이 있다면 개념 콕으로 정리해보세요.
 
현대의 자바 애플리케이션에서 데이터 지속성(persistence)은 중요합니다. 데이터 지속성이란 애플리케이션에서 생성되고 조작되는 데이터를 영구적으로 저장하고 관리하는 것을 의미합니다. 이를 통해 애플리케이션은 데이터의 무결성을 유지하고, 장기적으로 데이터를 보관하며, 필요할 때마다 데이터를 검색하고 활용할 수 있습니다.
전통적으로 자바 애플리케이션에서는 JDBC(Java Database Connectivity)를 사용하여 데이터베이스와 상호작용해 왔습니다. 하지만 JDBC를 직접 사용하는 것은 몇 가지 한계와 문제점을 가지고 있습니다. 반복적이고 boilerplate한 코드 작성, 객체 지향 프로그래밍과 관계형 데이터베이스 간의 불일치, 그리고 데이터베이스에 종속적인 코드 등이 대표적인 문제점입니다.
이러한 문제를 해결하기 위해 JPA(Java Persistence API)가 등장했습니다. JPA는 자바 애플리케이션에서 관계형 데이터베이스를 사용하는 방식을 표준화한 API입니다. JPA를 사용하면 개발자는 객체 지향적인 방식으로 데이터를 다룰 수 있으며, 데이터베이스에 대한 종속성을 줄일 수 있습니다.
JPA는 ORM(Object-Relational Mapping) 기술을 기반으로 합니다. ORM은 객체와 관계형 데이터베이스 간의 매핑을 자동화하여 개발자의 생산성을 높이고, 유지보수성을 향상시킵니다. JPA는 ORM의 장점을 활용하면서도, 표준 API를 제공하여 다양한 구현체를 사용할 수 있는 유연성을 제공합니다. 따라서 이번 아티클에서는 ORM과 대표적인 JPA 구현체인 Hibernate부터 JPA까지 모두 알아봅시다.
 
 

ORM(Object-Relational Mapping)

ORM이란?

객체 지향 프로그래밍 언어에서 사용되는 객체와 관계형 데이터베이스의 데이터 간의 매핑을 자동화하는 기법입니다. 개발자는 객체 지향 프로그래밍의 장점을 유지하면서 데이터베이스와의 상호작용을 쉽게 처리할 수 있습니다.
ORM은 데이터베이스 테이블의 행을 객체로, 열을 객체의 속성으로 매핑하여 객체 지향 방식으로 데이터베이스를 조작할 수 있게 해줍니다.
 

ORM 핵심 개념

  • 매핑
    • 객체와 데이터베이스 테이블 간의 대응 관계를 설정합니다.
    • 자바 클래스의 필드는 데이터베이스 테이블의 열에 매핑됩니다.
  • 엔티티
    • 데이터베이스 테이블에 대응하는 객체입니다.
    • 각 엔티티 인스턴스는 데이터베이스 테이블의 한 행을 나타냅니다.
  • 속성
    • 엔티티 클래스의 필드는 데이터베이스 테이블의 열에 매핑됩니다.
    • 클래스의 name 속성은 테이블의 name 열에 매핑됩니다.
  • 연관 관계
    • 객체 간의 관계를 정의하고 이를 데이터베이스 테이블 간의 외래 키 관계로 매핑합니다.
    • 일대일, 일대다, 다대일, 다대다 관계가 있습니다.
 

ORM의 장점

  • 객체 지향 프로그래밍의 일관성 유지
    • 데이터베이스 접근 로직을 객체 지향 방식으로 작성할 수 있어 코드의 일관성을 유지할 수 있습니다.
  • 생산성 향상
    • CRUD 코드를 자동화하여 개발 생산성을 높입니다.
    • 복잡한 SQL 쿼리를 직접 작성하지 않아도 되므로 개발 속도가 빨라집니다.
  • 유지보수 용이성
    • 데이터베이스 스키마가 변경될 경우, 엔티티 클래스를 수정하여 쉽게 대응할 수 있습니다.
    • 비즈니스 로직과 데이터베이스 접근 로직의 분리로 유지보수가 용이해집니다.
 

Hibernate

Hibernate란?

Hibernate는 자바 프로그래밍 언어용 ORM 프레임워크로, 관계형 데이터베이스와 객체 지향 프로그래밍을 연결해줍니다.
Hibernate는 JPA(Java Persistence API)의 표준 구현체 중 하나로, 자바 객체와 데이터베이스 간의 매핑을 자동으로 처리하여 개발자가 데이터베이스와 상호작용할 때 복잡한 SQL 쿼리를 작성하지 않아도 되게 해줍니다.
 

Hibernate 핵심 개념

  • 객체-관계 매핑(ORM)
    • 자바 클래스와 데이터베이스 테이블 간의 매핑을 설정합니다.
    • 데이터베이스의 테이블을 자바 객체로, 테이블의 컬럼을 객체의 필드로 매핑합니다.
  • 데이터베이스 독립성
    • 데이터베이스에 종속되지 않으며, 다양한 데이터베이스 시스템을 지원합니다.
    • 데이터베이스 변경 시 코드 수정이 최소화됩니다.
  • 투명한 지속성
    • 데이터베이스에 접근하는 코드를 작성하지 않고도 객체의 상태를 데이터베이스에 자동으로 동기화합니다.
    • 엔티티 객체의 생명주기를 관리합니다.
  • HQL (Hibernate Query Language)
    • 객체 지향 쿼리 언어로, SQL과 유사하지만 테이블이 아닌 엔티티 객체를 대상으로 쿼리를 수행합니다.
    • 복잡한 조회, 집계 등을 객체 지향적으로 표현할 수 있습니다.
  • 캐싱
    • 1차 캐시와 2차 캐시를 지원하여 성능을 최적화합니다.
    • 자주 조회되는 데이터를 메모리에 저장하여 데이터베이스 접근을 줄입니다.
 

Hibernate의 장점과 단점

장점
  • 생산성
    • 복잡한 SQL 쿼리를 자동으로 생성하여 데이터베이스 접근 코드를 단순화합니다.
  • 유지보수성
    • 객체 모델을 기반으로 데이터베이스 스키마를 자동으로 생성 및 업데이트할 수 있어 유지보수가 용이합니다.
  • 이식성
    • 다양한 데이터베이스 시스템을 지원하여 데이터베이스 변경 시 코드 수정이 최소화됩니다.
단점
  • 학습 곡선
    • Hibernate의 다양한 기능과 설정을 이해하는 데 시간이 필요할 수 있습니다.
  • 성능 오버헤드
    • 자동화된 작업으로 인해 일부 성능 오버헤드가 발생할 수 있습니다. 이는 캐싱 및 튜닝을 통해 최적화할 수 있습니다.
 

엔티티 클래스 작성

Hibernate에서 객체와 테이블을 매핑하는 방법을 보여드리겠습니다.
import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; // getters and setters }
  • @Entity 어노테이션
    • 클래스 레벨에 적용되며, 해당 클래스가 JPA 엔티티임을 나타냅니다.
    • @Entity가 붙은 클래스는 데이터베이스 테이블과 매핑되며, Hibernate가 관리합니다.
  • @Id 어노테이션
    • 엔티티 클래스의 필드 중 기본 키(Primary Key)로 사용될 필드에 적용됩니다.
    • 기본 키는 각 엔티티 인스턴스를 고유하게 식별하는 역할을 합니다.
    • 예시에서는 id 필드가 기본 키로 설정되어 있습니다.
  • @GeneratedValue 어노테이션
    • 기본 키 값의 생성 전략을 지정하는 데 사용됩니다.
  • 필드와 컬럼 매핑
    • 기본적으로 Hibernate는 필드 이름과 동일한 이름의 데이터베이스 컬럼과 매핑합니다.
    • 따라서 name 필드는 "name" 컬럼과 매핑되고, email 필드는 "email" 컬럼과 매핑됩니다.
 

Hibernate 설정 파일 (hibernate.cfg.xml)

Hibernate 설정 파일인 hibernate.cfg.xml의 내용은 아래와 같습니다. 이 파일은 Hibernate의 동작을 구성하고 데이터베이스 연결 설정을 정의하는 데 사용됩니다.
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mydatabase</property> <property name="hibernate.connection.username">myuser</property> <property name="hibernate.connection.password">mypassword</property> <property name="hibernate.hbm2ddl.auto">update</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <!-- List of annotated classes --> <mapping class="com.example.User"/> </session-factory> </hibernate-configuration>

데이터베이스 연동 코드

아래 예시는 Hibernate를 사용하여 데이터베이스와 연동하는 기본적인 흐름, 즉 Hibernate가 객체와 관계형 데이터베이스 간의 매핑을 처리하는 코드입니다. SessionFactory를 생성하고, Session을 열어 트랜잭션을 시작한 후, 엔티티 객체를 생성 및 저장하고, 트랜잭션을 커밋한 후에 Session을 종료하는 과정을 나타냈습니다.
import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class Main { public static void main(String[] args) { // Hibernate 설정 파일로부터 SessionFactory 생성 SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); // Session을 사용하여 데이터베이스 작업 수행 Session session = sessionFactory.openSession(); session.beginTransaction(); User user = new User(); user.setName("John Doe"); user.setEmail("john.doe@example.com"); session.save(user); session.getTransaction().commit(); session.close(); } }
 
 

JPA(Java Persistence API)

JPA(Java Persistence API)는 자바 애플리케이션에서 객체 관계 매핑(ORM)을 사용하여 관계형 데이터베이스를 쉽게 다룰 수 있도록 해주는 자바 API입니다. JPA를 사용하면 자바 객체와 데이터베이스 테이블 간의 매핑을 정의하고, 데이터베이스의 데이터를 객체 형태로 다룰 수 있게 됩니다. 이를 통해 데이터베이스에 접근하는 코드를 단순화하고, 객체 지향적인 접근 방식을 유지할 수 있습니다.
 

JPA의 주요 구성 요소

  • Entity
    • 데이터베이스 테이블에 매핑되는 자바 클래스입니다. 각 엔티티 클래스는 @Entity 어노테이션으로 표시되며, 클래스의 필드는 테이블의 컬럼에 매핑됩니다.
  • Entity Manager
    • 엔티티를 생성, 수정, 삭제, 조회할 수 있는 인터페이스입니다. EntityManager는 JPA 컨텍스트에서 엔티티 객체를 관리합니다.
  • Persistence Unit
    • JPA 설정 정보가 포함된 단위입니다. persistence.xml 파일에 정의되며, 데이터베이스 연결 정보와 엔티티 클래스를 설정합니다.
 
JPA는 구현체를 제공하지 않는 표준 명세로, 대표적인 구현체로는 Hibernate, EclipseLink, OpenJPA 등이 있습니다. 이러한 구현체는 JPA 인터페이스를 구현하여 실제 데이터베이스 연동 작업을 수행합니다.
 

JPA의 주요 메서드

  • persist(Object entity) 새로운 엔티티를 데이터베이스에 저장합니다.
  • find(Class<T> entityClass, Object primaryKey)
    • 주어진 기본 키로 데이터베이스에서 엔티티를 조회합니다.
  • merge(Object entity) 데이터베이스에 이미 존재하는 엔티티를 업데이트합니다.
  • remove(Object entity) 엔티티를 데이터베이스에서 삭제합니다.
  • createQuery(String qlString) JPQL 쿼리를 실행하기 위해 Query 객체를 생성합니다.
  • createNamedQuery(String name)
    • 미리 정의된 네임드 쿼리를 실행하기 위해 Query 객체를 생성합니다.
  • getTransaction() 현재 트랜잭션을 반환합니다.
  • getReference(Class<T> entityClass, Object primaryKey)
    • 프록시 객체를 사용하여 지연 로딩 방식으로 엔티티를 조회합니다.
  • flush() 현재 영속성 컨텍스트의 변경 사항을 데이터베이스에 반영합니다.
  • clear() 영속성 컨텍스트를 초기화합니다.
  • close(): 엔티티 매니저를 닫습니다.
 

JPA로 엔티티 생성, 조회, 업데이트, 삭제하기

아래는 JPA를 사용하여 데이터베이스와 연동하는 방법입니다. User 엔티티를 정의하고, EntityManager를 사용하여 엔티티를 생성, 조회, 업데이트, 삭제하는 작업을 수행합니다.
 
User 엔티티 클래스
javaCopy code import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; // Getters and Setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
User 엔티티 클래스는 @Entity 어노테이션을 사용하여 JPA 엔티티로 표시됩니다. @Id 어노테이션은 엔티티의 기본 키를 나타내며, @GeneratedValue를 사용하여 기본 키 생성 전략을 지정합니다.
JPA 연동 코드
javaCopy code import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; public class Main { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-persistence-unit"); EntityManager em = emf.createEntityManager(); // 엔티티 생성 및 저장 em.getTransaction().begin(); User user = new User(); user.setName("John Doe"); user.setEmail("john.doe@example.com"); em.persist(user); em.getTransaction().commit(); // 엔티티 조회 User foundUser = em.find(User.class, user.getId()); System.out.println("Found User: " + foundUser.getName()); // 엔티티 업데이트 em.getTransaction().begin(); foundUser.setEmail("john.newemail@example.com"); em.merge(foundUser); em.getTransaction().commit(); // 엔티티 삭제 em.getTransaction().begin(); em.remove(foundUser); em.getTransaction().commit(); // 엔티티 매니저 및 팩토리 종료 em.close(); emf.close(); } }
EntityManagerFactory는 JPA의 핵심 클래스 중 하나로, 데이터베이스 연결 및 엔티티 매니저 생성을 관리합니다. EntityManager는 데이터베이스와의 상호작용을 담당하는 주요 인터페이스입니다.
 
위 예제에서는 다음과 같은 작업을 수행합니다:
  1. persist(Object entity): 새로운 User 엔티티를 데이터베이스에 저장합니다.
  1. find(Class<T> entityClass, Object primaryKey): 데이터베이스에서 User 엔티티를 기본 키를 통해 조회합니다.
  1. merge(Object entity): 기존 User 엔티티를 수정하고 데이터베이스에 반영합니다.
  1. remove(Object entity): 데이터베이스에서 User 엔티티를 삭제합니다.
각 작업은 EntityManager의 트랜잭션을 통해 수행되며, 트랜잭션은 반드시 begin()commit()을 호출하여 관리합니다.
 
 

Spring Data JPA

Spring에서 사용할 때에는 SimpleJpaRepository 등 Spring Data JPA에서 사용하는 Repository 구현체를 사용합니다.
import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository<User, Long> { }
 
아래와 같이 정의하면 자연스럽게 구현체가 생겨서 Service Layer에서 쓸 수 있습니다.
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; @Service public class UserService { @Autowired private UserRepository userRepository; public User saveUser(User user) { return userRepository.save(user); } public Optional<User> getUserById(Long id) { return userRepository.findById(id); } public List<User> getAllUsers() { return userRepository.findAll(); } public void deleteUser(Long id) { userRepository.deleteById(id); } }
 
 
 

내일배움캠프는 개발에 필요한 핵심만 배웁니다

지금까지 꼭 필요한 개발 지식에 대해 알아보았습니다. 내일배움캠프에서는 전문가들이 선별한 핵심 개발 지식으로 개발 공부도, 취업도 보다 효율적으로 할 수 있는데요. 국내 유수의 IT기업 출신 튜터님들과 실습 위주의 독보적인 커리큘럼으로 개발자 취업을 체계적으로 준비해보세요. 내일배움캠프 4개월, 여러분 인생의 가장 큰 터닝 포인트입니다.
 
 
 
CREDIT
글 | 김민선 내일배움캠프 수료생 편집 | 정효재 팀스파르타 에디터
 
 

취업 준비, 어디서부터 시작해야 할지 모르겠다면?

 
🧐비전공자인데 IT 업계 취업할 수 있을까?
😟프로젝트 경험이 부족한데, 어떻게 준비해야 할까?
🥺IT 기업으로 이직하고 싶은데 뭐부터 시작해야 할까?
 
이런 고민을 하고 있다면, 내일배움캠프의 IT 취업 컨설팅을 받아보세요.
취업 코칭 전문가들이 여러분의 고민을 해결해 드립니다.
 
다음 링크에 이메일을 입력하시면 메일로 1:1 커리어 상담권과 취준 자료집을 보내드릴게요.
 
 
 
Share article
Subscribe to our newsletter

내일배움캠프 블로그