Backend & Spring (스프링)

Spring Data JPA와 Hibernate. 그리고 Persistence

jw92 2022. 11. 4. 15:04

1. Spring Data JPA, JPA, Hibernate와 JDBC

 

JPA (JAVA Persistence API): 자바에서 ORM에 대한 API 표준 명세(Interface)

(ORM: Object Relational Mapping, OOP 언어에서 관계형 데이터베이스를 사용하는 방식)

예를 들면 SELECT * FROM user; -> user.findAll()

Interface만 정의한 부분이기때문에 실제 구현부는 HIbernate 등 여러가지 중 선택할 수 있다.

일반적으로 HIbernate를 사용.

 

Hibernate: JPA의 구현체. JPA에서 사용되는 EntityManager, EntityManagerFactory와 EntityTransaction 등을 JDBC 기반으로 구현.

실제 구현 부분을 보면 Hibernate의 SessionFactory가 EntityManagerFactory를, Session이 EntityManager를 그리고 Transaction이 EntityTransaction을 상속한다.

SessionFactory의 실제 구현부분.

https://github.com/hibernate/hibernate-orm/blob/main/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java

 

Spring Data JPA(Repository): JPA를 한 단계 더 Abstraction.

JPA에서 사용하는 EntityManager를 사용하지 않고 Repository를 사용한다는 것이 가장 중요한 점.

아래와 같은 method를 구현하지 않고 사용할 수 있다.

findBy속성 ( ex) findById, findByName )

findBy속성1And속성2 ( ex) findByNameAndGender )

countBy ( ex) countByName )

 

Spring Data JPA를 사용하기 위해서는 @Entity를 선언한다.

Entity란 DB의 Table에존재하는 Column을 가지는 클래스의 객체이다. 추가적인 Field나 다른 Class를 상속해서는 안 된다.

 

2. DAO와 Repository

DAO와 Repository 모두 Persistence 로직에 대한 Interface를 제공한다는 점에서 하는 역할은 같다.

Domain과 Persistence Layer를 분리하여 Separation of Concerns를 달성하는 것이다.

 

하지만 DAO는 Persistence Logic의 요구사항에 의해 구현되어 CRUD에 매칭되는 Interface를 제공하지만,

Repository는 DDD (Domain-Driven Design)에 대해 GRASP 원칙 중 하나인 Pure Fabrication을 제공하기 위해 Domain의 요구사항을 처리하기 위한 Interface를 제공한다는 점이다.

(GRASP 참조 - https://jw92.tistory.com/15)

예를 들어 Repository에서는 특정 Interface가 조회와 업데이트를 수행한다고 하면, 이는 DAO의 R과 D에 매칭될 것이다.

이러한 차이로 인하여 Repository는 Domain layer에, DAO는 Persistencey layer로 분류한다.

 

Repository가 DAO를 호출한다는 얘기는 아니고 기능적으로 Repository:DAO = 1:N으로 매칭된다는 것이다,

Repository(Spring Data JPA)는 JPA( -> Hibernate -> JDBC -> DB)를 사용하므로 DAO가 사용되지 않을 것이다.

 

즉, DAO와 Repository는 혼동되기 쉽지만 개념적으로 다르므로, 서로를 보완한다거나 베타적이지는 않다.

일반적으로는 Spring에서는 DAO와 Repository 중 하나를 택하여 사용할 것이고, Repository를 더 많이 이용하게 될 것이다!! * 위에서 살펴본 Sprign Data JPA..!

 

번외. Hibernate와 DAO

Hibernate는 ORM의 구현체이다.

DAO를 구현할 수 있는 방법은 여러가지가 있다. 이 중 Hibernate를 이용한 구현도 가능할 것이다.
하지만 앞서 말한 것 처럼 우리는 일반적으로 JPA를 사용하므로 DAO를 사용하지 않을 것이다.

(하지만 RDB가 아닌 NoSQL 등을 사용한다면 DAO를 사용하게 될 가능성이 높다.)

public class Application
{
    private UserDao userDao;

    public Application(UserDao dao)
    {
        // Get the actual implementation
        // e.g. through dependency injection
        this.userDao = dao;
    }

    public void login()
    {
        // No matter from where
        User = userDao.findByUsername("Dummy");
    }
}


public interface UserDao
{
    User findByUsername(String name);
}

public class HibernateUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Do some Hibernate specific stuff
        this.session.createQuery...
    }
}

public class SqlUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        String query = "SELECT * FROM users WHERE name = '" + name + "'";
        // Execute SQL query and do mapping to the object
    }
}

public class LdapUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Get this from LDAP directory
    }
}

public class NoSqlUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Do something
    }
}

 

 

3. Persistence Context

Persistence Conetxt란 Application과 Pesistent Storage 사이에서 database로부터 entity를 가져오거나 entity를 database로 저장하는 1차 캐시이다.

Persistence Context란 모든 변화를 managed entity에 가지고 있어, 만약 transaction 내에서 어떠한 변화라도 일어나면 dirty로 마킹해서 transaction이 종료되면 모든 변경을 persistent storage에 저장된다.

 

JPA Entity Life Cycle

https://docs.oracle.com/cd/E16439_01/doc.1013/e13981/undejbs003.htm

1. New(Transient): 객체를 생성만 한 상태. Persistence Conext에 속하지 않는다.

2. Managed: Entity Manager에 의해 관리되고 있는 상태. persist 혹은 find, getReference를 호출하면 managed 상태가 된다.

3. Detached: Entity Manager가 종료되거나 clear, detach를 호출하는 경우. Detached에서 merge를 호출하면 다시 managed가 된다.

4. Removed: remove를 호출하는 경우. 트랜잭션이 커밋될 때 데이터베이스에서 해당 엔티티가 삭제된다.

 

Entity Class 내부에 아래 callback annotation을 통해 상태변화에 따라 특정 작업을 수행할 수 있다.

  • @PrePersist: persist()가 호출되어 엔티티가 관리되는 상태로 전환되기 전 호출
  • @PostPersist: 엔티티가 관리되는 상태로 전환된 후 호출
  • @PreUpdate: 엔티티가 데이터베이스에 업데이트되기 전 호출
  • @PostUpdate: 엔티티가 데이터베이스에 업데이트된 후 호출
  • @PreRemove: 엔티티가 삭제되기 전 호출
  • @PostRemove: 엔티티가 삭제된 후 호출
  • @PostLoad: 엔티티가 데이터베이스에서 로드된 후(조회된 후) 호출

 

 

참고. 트랜잭션 격리 수준 (Transaction Isolation Level)

2024.07.07 - [Data] - 트랜잭션 격리 수준 / Transaction Isolation Level

'Backend & Spring (스프링)' 카테고리의 다른 글

Spring의 Inversion of Control (IoC) 과 Dependency Injection (DI)  (0) 2022.11.13
Spring Framework  (0) 2022.10.14
Spring Boot이란?  (0) 2022.10.14
Spring 이란?  (0) 2022.10.14
API 게이트웨이와 Spring Cloud Zuul Filter  (0) 2022.10.13