ORM 이란?

🌎·2023년 5월 15일
0

스프링 공부

목록 보기
4/11
post-thumbnail

1. ORM

ORM(Object-Relational Mapping)은 대체 무엇일까?
이것은 자바의 객체와 데이터베이스(이하, 디비)를 연결하는 프로그래밍 기법이다.
예를 들어, 자바의 객체로 Board라는 객체가 있고 title, content 필드가 있다고 가정해보자. 이것을 디비로부터 값을 받아와서 넣어주려면 SQL 쿼리를 이용해야 한다. 그러면 우리는 또 SQL을 공부하는 번거로움을 갖게 된다.
(그런데 나는 사실 SQL을 아주 좋아한다...)

아무튼!
ORM은 이런 번거로움을 없애주고 디비의 값을 마치 객체처럼 사용할 수 있게 해준다.
즉, SQL 공부를 하지 않아도 자바 언어로 디비 값을 조회 및 조작할 수 있게 되는 것이다.
이걸 해줄 수 있게 해주는 도구가 바로 ORM이다.

그런데 어렵고 복잡한 쿼리문 같은 경우는 자바 코드로 치는데 한계가 있을 것이다. 이것은 어쩔 수 없다고 생각한다... (편리함 대신 얻는 대가랄까...)

2. JPA와 Hibernate

스프링을 돌리다보면 JPA, Hibernate 단어를 많이 접하게 된다.
나같은 경우도 JPA, JPA 거리기만 했지 정말 JPA가 무엇이고, Hibernate가 무엇인지 잘 몰랐다.
오늘의 공부를 통해 확실히 알아가도록 하자.

JPA자바에서 RDBMS를 사용하는 방식을 정의한 인터페이스이다. 인터페이스이기 때문에 이를 실제로 사용하기 위한 구현체를 추가로 갖춰야하는데 그 중 하나가 Hibernate되겠다.

즉, Hibernate = JPA 인터페이스를 구현한 구현체이자 자바용 ORM 프레임워크 이다.

3. 엔티티 매니저 + 영속성 컨텍스트

엔티티 매니저와 영속성 컨텍스트는 JPA의 중요한 컨셉 중 하나이다.

엔티티

엔티티는 디비의 테이블과 매핑되는 객체를 의미한다.
디비의 테이블과 직접 연결된다는 특징이 있어서 자바 객체와 다르게 엔티티라고 따로 지칭한다.

엔티티 매니저

엔티티 매니저는 엔티티를 관리해 디비와 어플리케이션 사이에서 객체를 생성, 수정, 삭제하는 등의 역할을 한다. 이런 엔티티 매니저를 만드는 곳이 엔티티 매니저 팩토리이다.
만약에 회원 두 명이 동시에 책을 빌리면, 회원 1의 요청에 대응해줄 엔티티 매니저와, 회원 2의 요청에 대응해줄 엔티티 매니저를 엔티티 매니저 팩토리에서 각각 생성해주는 것이다.
그리고 이렇게 생성된 엔티티 매니저들은 필요한 시점에 디비와 연결한 뒤에 쿼리를 실행한다.

BUT, 스프링 부트에서는 직접 엔티티 매니저 팩토리를 만들어서 관리하지 않고, 스프링 부트 내부에서 엔티티 매니저 팩토리를 하나만 생성해서 관리하고 @PersistenceContext 또는 @Autowired
어노테이션을 통해 엔티티 매니저를 사용한다.

그리고 스프링 부트는 기본적으로 빈은 하나만 생성해서 공유하므로 동시성 문제가 발생할 수 있다. 그래서 실제로는 엔티티 매니저가 아닌 실제 엔티티 매니저와 연결하는 프록시(가짜)엔티티 매니저를 사용한다. 필요할 때 디비 트랜잭션과 관련된 실제 엔티티 매니저를 호출하는 것이다.

쉽게 말해 엔티티 매니저는 Spring Data JPA 에서 관리하므로 우리가 직접 생성하거나 관리할 필요가 없다.

그리고 추가적으로 엔티티 매니저는 기본적으로 UPDATE를 제공하지 않는다. JPA는 트랜잭션의 범위에서 엔티티 객체의 상태가 변경되면 이를 트랜잭션 커밋 시점에 반영한다.

영속성 컨텍스트

영속성 컨텍스트는 JPA의 중요한 특징 중 하나로, 엔티티를 관리하는 가상의 공간이다.
영속성 컨텍스트는 아래와 같은 특징을 가지고 있다.

  1. 1차 캐시
    영속성 컨텍스트는 내부에 1차 캐시를 가지고 있다. 이 때 키는 @Id 어노테이션이 달린 필드 값이 되겠다. 엔티티를 조회하면 1차 캐시에서 먼저 조회해 값을 반환한다. 1차 캐시에 값이 없으면 디비에서 조회해 1차 캐시에 저장하고 반환한다.
  2. 쓰기 지연
    쓰기 지연은 트랜잭션을 커밋하기 전까지는 실제로 디비에 질의문을 보내지 않고 쿼리를 모아두었다가 트랜잭션을 커밋할 때 한 번에 실행하는 것을 말한다. 이를 통해 디비 시스템의 위험 부담을 줄일 수 있다.
  3. 변경 감지
    트랜잭션을 커밋하면 1차 캐시에 저장되어 있는 엔티티의 값과 현재 엔티티의 값을 비교해서 변경된 값이 있다면 변경사항을 감지해 변경된 값을 디비에 자동으로 반영한다.
  4. 지연 로딩
    지연로딩은 쿼리로 요청한 데이터를 어플리케이션에 바로 로딩하는 것이 아니라 필요할 때 쿼리를 날려 데이터를 조회하는 것을 말한다. 반대로 조회할 때 쿼리를 보내 연관된 모든 데이터를 가져오는 즉시 로딩도 있다.

엔티티의 생명주기

업로드중..

public class EntityManagerTest {

	@Autowired
    EntityManager em;
    
    public void example() {
    	// 엔티티 매니저가 엔티티를 관리하지 않는 상태 = 비영속 상태
		Member member = new Member(1L, "홍길동");
        
        // 엔티티가 관리 상태가 됨 = 관리 상태
        em.persist(member);
        
        // 엔티티 객체가 분리된 상태가 됨 = 분리 상태
        em.detach(member);
        
        // 엔티티 객체가 삭제된 상태가 됨 = 삭제 상태
        em.remove(member);
    }

}
  • 비영속 상태
    엔티티 객체를 생성했지만 아직 영속성 컨텍스트에 저장하지 않은 상태

  • 영속 상태
    엔티티 매니저를 통해서 엔티티를 영속성 컨텍스트에 저장한 상태를 말하며 엔티티 매니저에 의해 관리된다.

  • 준영속 상태
    영속 상태의 엔티티를 더이상 관리하지 않는 상태이다.
    1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩을 포함한 영속성 컨텍스트가 제공하는 어떠한 기능도 동작하지 않는다.
    식별자 값을 가지고 있다.

  • 삭제
    엔티티를 영속성 컨텍스트와 디비에서 삭제한다.

4. 스프링 데이터 JPA

위와 같은 코드들을 개발자가 계속 작성해가면서 관리하면 매우 번거로울 것이다.
스프링 데이터는 비즈니스 로직에 더 집중할 수 있게 디비 사용 기능을 클래스 레벨에서 추상화하였다.

이전까지는 아래와 같이 메서드 호출로 엔티티 상태를 바꿔주었다.

@PersistenceContext
EntityManager em;

public void join() {
	Member member = new Member(1L, "홍길동");
    em.persist(member);
}

이제 스프링 데이터 JPA를 사용하면 아래와 같이 하면 된다.

public interface MemberRepository extends JPARepository<Member, Log> {
}

끝 -*



참고자료

엔티티와 엔티티매니저
JPA, Hibernate, 그리고 Spring Data JPA의 차이점
What is ORM, how does it work?
JPA 영속성 컨텍스트란?
[도서] 스프링 부터 3 백엔드 개발자 되기

profile
영차영차

0개의 댓글