ORM은 Object-Relational-Mapping의 약자로 자바의 객체와 데이터베이스를 연결하는 프로그래밍 기법이다.
ORM은 데이터베이스의 값을 객체처럼 사용한다. 따라서 SQL을 몰라도 자바 언어만으로 데이터베이스에 접근하여 데이터를 활용할 수 있다.
즉, ORM은 자바 언어로 데이터베이스를 다룰 수 있게 해주는 도구이다.
ORM 장점
SQL을 직접 작성하지 않고 기존에 사용하던 언어로 데이터베이스에 접근할 수 있다.
객체 지향적으로 코드를 작성할 수 있어 비즈니스 로직에만 집중할 수 있다.
데이터베이스 시스템이 추상화 되어 있어
매핑하는 정보가 명확하기 때문에 ERD에 대한 의존도를 낮출 수 있고 유지보수할 때 유리하다.
ORM 단점
ORM에도 여러 종류가 존재하는데, 자바에서는 JPA(Java Persistence API)를 표준으로 사용한다.
JPA는 자바에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스이다.
ORM 프레임워크를 통해 구현
대표적인 ORM 프레임워크 중 하이버네이트(Hibernate)를 많이 사용한다.
하이버네이트는 JPA 인터페이스를 구현한 구현체이자 자바용 ORM 프레임워크이다.
내부적으로는 JDBC API를 사용한다.
자바 객체를 통해 데이터베이스 종류에 상관없이 데이터베이스를 자유롭게 사용할 수 있게 해준다.
- JPA와 Hibernate의 역할
- JPA
자바 객체와 데이터베이스를 연결해 데이터를 관리한다.
- Hibernate
JPA 인터페이스를 구현한다.
- JDBC API
Java Database Connectivity의 약자로 자바 프로그램이 데이터베이스와 연결되어 데이터를 주고 받을 수 있도록 해주는 인터페이스이다.또한 JDBC API는 표준 응용 프로그래밍의 인터페이스만을 제공하고, 실질적인 인터페이스의 메소드 기능들에 대한 실제 구현은 각 DBMS 제조사들이 자신들의 데이터베이스에 맞게 구현하여 제공하며, 이를 JDBC 드라이버라고 한다.
즉, JDBC 드라이버란 DBMS 회사들이 자신들의 데이터베이스 시스템에 접근할 수 있도록 표준 JDBC 인터페이스에 명시된 메소드들을 구현한 것이다.
Entity
엔티티는 데이터베이스의 테이블과 매핑되는 객체를 의미한다. 일반 객체와 다르지는 않지만, 데이터베이스의 테이블과 직접 연결된다는 아주 특별한 특징이 있어 구분지어 명명한다. 즉, 데이터베이스에 영향을 미치는 쿼리를 실행하는 객체를 의미한다.
Entity Manager
엔티티를 관리해 데이터베이스와 어플리케이션 사이에서 객체를 생성, 수정, 삭제하는 등의 역할을 한다.
엔티티 매니저를 생성하는 곳이 엔티티 매니저 팩토리(Entity Manger Factory)이다.
하지만 스프링 부트에서는 엔티티 매니저 팩토리를 직접 만들어서 관리하지 않는다. 스프링 부트 내부에서는 엔티티 매니저 팩토리를 하나만 생성해서 관리하고, 다음과 같이 @PersistenceContext 또는 @Autowired 애너테이션을 사용해서 엔티티 매니저를 사용한다.
@PersistenceContext
EntityManager em;
cf. 엔티티 매니저는 Spring Data JPA에서 관리 하므로 생성하거나 직접 관리할 필요는 없다.
엔티티 매니저가 엔티티를 저장하고 관리하는 가상의 공간이다.
영속성 컨텍스트에는 1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩 특징이 존재한다.
1차 캐시
영속성 컨텍스트는 내부에 존재한다.
캐시의 키는 엔터티의 @Id 애너테이션이 달린 기본키 역할을 하는 식별자이며, 값은 엔터티이다.
엔터티 조회시 1차 캐시에 먼저 테이터를 조회 후 값이 있으면 반환하고, 값이 없을 시 데이터베이스에서 조회 후 1차 캐시에 저장 후 반환한다.
1차 캐시를 통해 캐시된 데이터에는 데이터베이스를 거치지 않고 더 빠르게 접근할 수 있다.
쓰기 지연 (Transactional write-behind)
트랜잭션을 커밋하기 전까지는 데이터베이스에 반영하지 않고 쿼리를 모은 후, 커밋이 이루어질시 쿼리를 한번에 실행하는 것을 의미한다.
이를 통해 적당한 단위로 쿼리를 요청할 수 있어 데이터베이스 시스템의 과부하를 줄일 수 있다.
변경 감지
트랜잭션 커밋 시 1차 캐시에 저장된 값과 현재 엔티티의 값을 비교하여 최신화 한 후 데이터베이스에 자동으로 반영한다.
이를 통해 적당한 단위로 쿼리를 요청할 수 있어 데이터베이스 시스템의 과부하를 줄일 수 있다.
지연 로딩 (lazy loading)
반대로 조회할 때 쿼리를 보내 연관된 모든 데이터를 가져오는 즉시 로딩도 존재한다.
위 특징들로 인해 캐시를 하거나, 자주 쓰지 않게 하거나, 변화를 감지해서 자동으로 반영하는 등 데이터베이스의 접근을 최소화해 성능을 높일 수 있다.
엔티티는 다음 4가지의 상태가 존재한다.
public class EntityManagerTest {
@Autowired
EntityManager em;
public void example() {
Member member = new Member(1L, "홍길동"); // 비영속 상태 - a
em.persist(member); // 관리 상태 - b
em.detach(member); // 분리 상태 - c
em.remove(member); // 삭제 상태 - d
}
}
a : 엔티티를 처음 만들면 비영속 상태가 된다.
b : persist() 메소드를 이용해 엔티티를 관리 상태로 만들 수 있으며, Member 객체는 영속성 컨텍스트에서 상태가 관리된다.
c : detach() 메소드를 이용해 영속성 컨텍스트에서 관리하지 않도록 분리할 수 있다.
d : remove() 메소드를 이용해 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제할 수 있다.
[추가 참고]
JDBC API : https://aomee0880.tistory.com/132