데이터 지속성(Data persistence)은 대부분의 애플리케이션에서 매우 중요합니다. 애플리케이션이 데이터를 지속적으로 저장할 필요는 없지만, 비디오 게임, 소셜 미디어 플랫폼 또는 블로깅 웹사이트와 같은 다양한 분야의 대규모 애플리케이션에서는 흔히 사용하는 관행입니다.
Java에서 데이터 지속성은 시간이 지남에 따라 많은 관심을 받았으며, 눈에 띄는 발전을 이뤄왔습니다. 처음에는 JDBC API를 직접 사용하는 것에서 시작하여, 점점 더 추상화되고 개발자가 사용하기 쉬운 표준화된 메커니즘으로 발전해왔습니다.
이러한 진화 과정에서 많은 지속성 기술이 개발되었으며, 이들 간의 차이는 종종 개발자들 사이에서 혼란을 일으킬 수 있습니다. 이러한 기술로는 Hibernate, JPA, Spring Data JPA가 있습니다.
개발할 때 이 중 하나를 선택해야 할까요? 아니면 이들 모두를 동시에 사용할 수 있을까요?
하나씩 살펴보겠습니다.
Hibernate
Hibernate는 가장 인기 있는 Java ORM(Object Relational Mapping) 프레임워크 중 하나로, Java 애플리케이션과 데이터베이스 간의 상호작용을 보다 효율적으로 관리하기 위해 사용됩니다. 이 프레임워크는 Java 클래스와 데이터베이스 테이블을 양방향으로 매핑할 수 있으며, 객체/관계 불일치 문제에 대한 완전한 솔루션을 제공합니다.
Hibernate는 주석(annotations)을 사용하여 매핑이 이루어지는 메타데이터를 생성합니다. 가장 많이 사용되는 주석 중 일부는 아래에 나와 있습니다.
@Entity
@Table(name = "CAR")
public class Car {
@Id
@Column(name = "CAR_ID")
private Long cardId;
@Column(name = "COLOR")
private String color;
@ManyToOne()
@JoinColumn(name = "OWNER_ID")
private Owner owner;
}
- @Entity은 클래스를 엔티티 빈으로 표시하는 데 사용됩니다.
- @Table은 데이터베이스 테이블의 이름 및 스키마 등을 설정하는 데 사용됩니다.
- @Id은 속성을 기본 키로 표시하는 데 사용됩니다.
- @Column은 데이터베이스 열의 이름과 해당 속성에 대한 세부 정보를 설정하는 데 사용됩니다.
- @ManyToOne은 두 엔티티 간의 관계를 생성하는 데 사용됩니다. 이 경우, 관계는 다대일(many-to-one)입니다.
- @JoinColumn은 관계가 생성되는 외래 키 열의 이름을 정의하는 데 사용됩니다.
Hibernate의 핵심 부분 중 하나는 Session 인터페이스입니다. 세션(Session)은 SessionFactory에 의해 생성되고 관리됩니다. 이 세션은 쿼리 작성, CRUD 작업 수행, 트랜잭션 관리 등을 가능하게 합니다. Session의 가장 중요한 메서드들은 다음과 같습니다:
/*
* Used to save a new object to the database
*/
Object save(Object var1);
/*
* Used to update an object in the database
*/
void update(Object var1);
/*
* Used to delete an object from the database
*/
void delete(Object var1);
/*
* Gets an object from the database
*/
<T> T get(Class<T> var1, Object var2);
/*
* Creates a new SQL query to be executed
*/
Query createQuery(String var1);
/*
* Used to start a new database transaction
*/
Transaction beginTransaction();
Hibernate는 데이터베이스와 통신하기 위해 JDBC API를 사용합니다. Hibernate는 JDBC API의 많은 복잡성을 추상화하여 개발자가 데이터베이스 연결 과정을 신경 쓰지 않고 직접 Java 객체로 작업할 수 있게 합니다.
Hibernate가 Java에서 매우 인기가 있는 이유는 몇 가지 장점 때문입니다:
- 생산성: 대부분의 구현이 개발자에게 숨겨져 있어 비즈니스 문제에 대한 최선의 해결책에 집중하기가 훨씬 쉬워집니다.
- 성능: Hibernate는 캐싱(caching) 및 배칭(batching)과 같은 여러 최적화 메커니즘을 사용합니다.
- 직관성: 대부분의 작업을 애노테이션을 통해 수행하므로 쉽게 이해할 수 있는 코드를 작성할 수 있습니다.
Hibernate는 시간이 지나면서 JPA 표준을 준수하고 그 메서드를 구현하게 되었습니다. 또한, Hibernate는 이전 버전과의 호환성을 유지하고 일부 고유한 기능을 계속 사용하기 위해 자체적인 구현도 유지하고 있습니다. 그렇다면 여기서 말하는 JPA란 무엇일까요?
JPA
JPA(Java Persistence API)는 규격이자, Java에서 데이터를 지속적으로 저장하는 표준화된 메커니즘의 일부가 되고자 하는 ORM 프레임워크가 구현해야 하는 일련의 규칙입니다.
JPA는 Hibernate와 같은 프레임워크가 아니라, ORM 프레임워크가 구현해야 하는 인터페이스에 불과합니다.
JPA의 주요 목적 중 하나는 Java에서 데이터를 지속적으로 저장하기 위한 표준적인 접근 방식을 만드는 것입니다. 이는 JPA를 구현한 ORM 프레임워크 간의 상호 운용성을 향상시킵니다. 예를 들어, 애플리케이션이 Hibernate를 ORM 프레임워크로 사용하고 있다가 나중에 다른 ORM 도구(예: EclipseLink)로 교체해야 한다고 가정해봅시다. 두 프레임워크가 모두 JPA 표준을 준수한다면, 한 프레임워크에서 다른 프레임워크로의 전환이 더 쉬워집니다. 그러나 전환이 쉬워지더라도 한 프레임워크의 고유한 구현이 다른 프레임워크에 존재하지 않을 수 있다는 점은 주목할 만합니다(예를 들어 Hibernate의 경우처럼).
JPA는 지속성 프로세스를 관리하기 위해 EntityManager와 EntityManagerFactory에 의존합니다. EntityManager는 엔티티의 상태 변화를 관리하고 이를 SQL 쿼리로 변환하는 Persistence Context로 작동합니다. EntityManager의 주요 메서드는 다음과 같습니다:
/*
* Returns an entity by its primary key.
*/
public <T> T find(Class<T> entityClass, Object primaryKey);
/*
* Creates a new transient entity that will be inserted in the databse during
* the next flush()
*/
public void persist(Object entity);
/*
* Transforms a detached entity (an entity that was managed by a Persistence
* Context at some point) into a transient one
*/
public <T> T merge(T entity);
/*
* Removes the entity from database at the next flush() operation
*/
public void remove(Object entity);
/*
* Synchronizes the Persistence Context with the underlying database
*/
public void flush();
JPA는 또한 새로운 언어인 Java Persistence Query Language(JPQL)를 도입합니다. JPQL은 문자열 쿼리를 작성할 필요 없이 SQL 쿼리를 구축할 수 있는 가능성을 열어줌으로써, 순수 SQL로 작업할 필요를 더욱 줄이고 Java 개발자들에게 코딩 경험을 보다 직관적으로 만들어 줍니다.
JPA의 주요 장점은 다음과 같습니다:
- 상호 운용성(Interportability): 두 프레임워크가 JPA를 준수하는 경우, 한 ORM 프레임워크에서 다른 프레임워크로 이동하는 과정이 훨씬 쉬워집니다.
- 사용 편의성(Usability): JPQL이 쿼리를 정의할 때 엔티티 클래스와 그 필드를 인식할 수 있기 때문에 SQL 쿼리 작성이 더욱 쉬워집니다.
이제 Hibernate와 JPA 간의 관계가 명확해졌으니, Spring Data JPA로 넘어가 보겠습니다.
Spring Data JPA
Hibernate와 JPA가 모든 Java 애플리케이션에서 사용할 수 있는 반면, Spring Data JPA는 Spring 애플리케이션의 일부로 사용됩니다. Spring Data JPA는 Spring Data 프로젝트의 일부로, 리포지토리를 생성하는 데 필요한 상용구 코드를 줄여줌으로써 Spring 애플리케이션에서 데이터베이스 작업의 복잡성을 줄이는 것을 목표로 합니다. 이는 JPA 작업을 더욱 생산적으로 만들어주는 추가적인 추상화 수준을 제공합니다.
Spring Data JPA의 핵심은 JpaRepository입니다. 이 인터페이스는 개발자에게 매우 유용한 기능을 제공하며, CRUD 작업, 정렬, 페이징과 같은 기능을 기본적으로 제공합니다. JpaRepository는 두 가지 제네릭 매개변수를 가지는데, 하나는 엔티티 클래스이고 다른 하나는 해당 엔티티의 기본 키 타입입니다. 이 인터페이스는 ListCrudRepository,
ListPagingAndSortingRepository와 같은 유용한 리포지토리들을 확장합니다. 최종적으로, 모든 리포지토리 인터페이스는 Repository 인터페이스를 확장하는데, 이 인터페이스는 메서드가 없으며 리포지토리 인터페이스의 마커로만 사용됩니다.
Spring Data JPA의 가장 큰 장점 중 하나는 Spring의 기능을 활용하여, SimpleJpaRepository의 도움으로 리포지토리의 구현이 런타임에 자동으로 이루어진다는 점입니다. 개발자가 영속성 데이터에 액세스하기 위해 새로운 리포지토리를 만들고자 할 때, JpaRepository를 확장하는 인터페이스만 작성하면 모든 메서드가 자동으로 구현됩니다. 정말 편리하죠!
결론
글의 초반에 제기된 질문에 대한 답은 다음과 같습니다:
네, Hibernate, JPA 및 Spring Data JPA는 각자가 개발 단계에서 다른 목적을 가지므로, 그 유사성에도 불구하고 함께 사용할 수 있습니다.
'레퍼런스' 카테고리의 다른 글
[Medium] 내가 원했던, Git 가이드 (2) (2) | 2024.09.29 |
---|---|
[Medium] 내가 원했던, Git 가이드 (1) (0) | 2024.08.28 |
[Medium] 유용한 무료 IntelliJ Plugin 5가지 (0) | 2024.07.25 |
[Medium] Java Spring Boot에서 If-Else문 줄이기 (0) | 2024.07.10 |
[Medium] Postgres vs MySQL (0) | 2024.06.26 |