DB

[DB] ORM(Object Relational Mapping) 이란?

bum0w0 2024. 8. 16. 16:06

1.  ORM (Object Relational Mapping)

객체 - 관계를 매핑한다는 의미이다.

 

객체 지향 프로그래밍에서는 클래스를 사용하지만, 관계형 데이터베이스는 테이블을 사용한다. 이 때 모델의 불일치가 일어나는데 ORM을 통해 객체 지향 프로그래밍 언어에서 사용되는 객체와 관계형 데이터베이스의 테이블 간 매핑을 자동화 할 수 있다. 

 

- SQL 쿼리를 직접 작성하지 않아도 데이터베이스 작업을 수행할 수 있다.

- 객체 지향 언어에서의 클래스와 객체를 데이터베이스 테이블과 레코드에 대응시켜 매핑

- 개발자는 객체를 통해 데이터베이스와 상호작용

 

이런 대표적인 ORM 프레임 워크로 Hibernate, JPA(Java Persistence API)등이 있다. 파이썬에서는 SQLAlchemy, Django ORM 등이 존재한다.

 

2.  Persistence (영속성)

데이터를 생성한 프로그램의 생명주기 동안만 유지되는 것이 아니라, 프로그램 종료 이후에도 데이터를 유지하고 사용할 수 있도록 하는 속성. (JDBC를 이용하여 영속성 부여 및 데이터베이스와 연동되는 시스템을 개발할 수 있지만 최근에는 Sping Data JPA, Hibernate, Mybatis 등이 널리 쓰이고 있다.)

 

- 주로 데이터베이스에 데이터를 저장하여 애플리케이션의 상태를 유지하는데 사용 (Ex. 회원 정보, 주문 내역 등을 유지시키는 것)

- 영속성을 관리하기 위한 프레임워크 기술로 위에서 언급한 Hibernate가 널리 사용된다. Hibernate는 ORM 프레임워크의 표준이자 JPA의 구현체(interface)라고도 부른다.

 

3.  장단점

그렇다면 ORM을 사용하는 이유가 무엇일까?

 

1. 앞서 SQL 쿼리문이 아닌 객체 지향적 코드로 데이터베이스 작업이 가능하다고 했는데 이는 개발자가 복잡한 쿼리문을 통해 CRUD를 구현하지 않아도 직관적인 객체 모델로 비즈니스 로직 구현하는 것에 더 집중할 수 있도록 도와준다.

 

2. ORM은 독립적으로 작성되고 객체를 재사용할 수 있기 때문에 재사용성과 유지보수의 편리함이 증가한다. 스프링에서는 모델(데이터베이스를 통해 가공된 데이터)을 컨트롤러가 뷰로 넘겨주는 MVC 디자인 패턴을 보이는데 이런 패턴을 더 견고하고 편리하게 구현할 수 있다.

 

3. 종속성이 줄어든다. 개발자가 객체 지향적으로 코드를 작성하면 그에 맞춰서 자동으로 SQL 쿼리를 생성하기 때문에 위에서 말한 모델의 불일치, 즉 관계형 데이터베이스의 데이터 구조와 객체지향 모델 간의 세계를 적절히 매핑하게 도와준다. 따라서 DB 자체에 대한 종속성이 줄어들고 이후에 DBMS를 교체하게 되는 큰 작업이 생기더라도 비교적 적은 노력을 들여 해결할 수 있게된다.

 

 

4. ORM 프레임워크 사용 (Spring Data JPA, 구현체는 Hibernate)

 

 Spring Data JPA와 Hibernate를 사용하여 데이터를 관리할 때는 Entity 클래스와 Repository 인터페이스로 나뉜다.

 

1. Entity 클래스 (매핑 클래스)

 

@Entity 어노테이션: 클래스를 엔티티로 지정

@Id 어노테이션: 엔티티의 기본 키를 지정

@GeneratedValue 어노테이션: 기본 키의 생성 전략을 지정

@Column: 데이터베이스의 열에 해당하는 변수들 지정

package board.spring_aws.domain.user;


import board.spring_aws.domain.BaseTimeEntity;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

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

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private String email;

    @Column
    private String picture;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private Role role;

    @Builder
    public User(String name, String email, String picture, Role role) {
        this.name = name;
        this. email = email;
        this.picture = picture;
        this.role = role;
    }

    public User update(String name, String picture) {
        this.name = name;
        this.picture = picture;

        return this;
    }

    public String getRoleKey() {
        return this.role.getKey();
    }
}

 

 

2. Repository 인터페이스

 

Spring Data JPA는 이 인터페이스를 통해 기본적인 CRUD(Create, Read, Update, Delete) 작업을 쉽게 구현할 수 있도록 지원한다.

JpaRepository<Entity, ID>를 상속받아 생성한다. 여기서 Entity는 엔티티 클래스이고, ID는 엔티티의 기본 키 타입이다.

package board.spring_aws.domain.user;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long> {

    // 필요하면 커스텀 쿼리 메소드를 추가
    Optional<User> findByEmail(String email);
}