JPA와 실제 구현체의 차이
JPA는 Java 진영에서 ORM을 지원하기 위한 스펙입니다. 즉, 실제 구현체는 따로 있고 JPA는 interface와 그 interface를 사용하는 방법을 제공할 뿐입니다. 그래서 실제로 ORM이 어떻게 이루어지는지 보려면 Hibernate 같은 구현체를 봐야 합니다.
여기서 JPA 아키텍처는, 이 JPA의 여러 구성 요소들과 이 구성 요소들이 어떻게 상호작용 하는지에 관한 내용입니다.
JPA Architecture의 큰 그림
우선 우리가 @Entity를 붙여서 JPA로 관리할 객체를 만들면 이 객체는 이제 JPA가 관리합니다. 정확히 어떻게 관리할까요?
EntityManager라는 객체를 보면 답이 나옵니다. 이 객체를 보면 JPA Entity의 생명 주기를 바꿀 수 있는 method 들이 잔뜩 있습니다. 이 객체를 통해 Entity를 관리하는 겁니다.
public interface EntityManager {
public void persist(Object entity);
public <T> T merge(T entity);
public void remove(Object entity);
public <T> T find(Class<T> entityClass, Object primaryKey);
public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties);
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode);
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties);
public <T> T getReference(Class<T> entityClass, Object primaryKey);\
public void flush();
public void detach(Object entity);
// 이하 생략
}
EntityManager는 EntityManagerFactory를 통해 받아올 수 있습니다. EntityManagerFactory는 굉장히 무거워서 보통 1개만 만들어서 공유해서 씁니다.
public interface EntityManagerFactory {
public EntityManager createEntityManager();
public EntityManager createEntityManager(Map map);
public EntityManager createEntityManager(SynchronizationType synchronizationType);
public EntityManager createEntityManager(SynchronizationType synchronizationType, Map map);
public CriteriaBuilder getCriteriaBuilder();
public Metamodel getMetamodel();
public boolean isOpen();
public void close();
public Map<String, Object> getProperties();
public Cache getCache();
public PersistenceUnitUtil getPersistenceUnitUtil();
public void addNamedQuery(String name, Query query);
public <T> T unwrap(Class<T> cls);
public <T> void addNamedEntityGraph(String graphName, EntityGraph<T> entityGraph);
}
저 EntityManagerFactory는 Persistence를 통해 받아 옵니다. 하지만 사실 Persistence가 하는 역할은 PersistenceProvider를 호출하는 것 뿐입니다.
public class Persistence {
public static EntityManagerFactory createEntityManagerFactory(String persistenceUnitName) {
return createEntityManagerFactory(persistenceUnitName, null);
}
public static EntityManagerFactory createEntityManagerFactory(String persistenceUnitName, Map properties) {
EntityManagerFactory emf = null;
PersistenceProviderResolver resolver = PersistenceProviderResolverHolder.getPersistenceProviderResolver();
List<PersistenceProvider> providers = resolver.getPersistenceProviders();
for (PersistenceProvider provider : providers) {
emf = provider.createEntityManagerFactory(persistenceUnitName, properties);
if (emf != null) {
break;
}
}
if (emf == null) {
throw new PersistenceException("No Persistence provider for EntityManager named " + persistenceUnitName);
}
return emf;
}
public static void generateSchema(String persistenceUnitName, Map map) {
// 생략
}
// 이하 생략
}
진짜 EntityManagerFactory를 만드는 건 PersistenceProvider입니다. 하지만 PersistenceProvider는 interface이기 때문에 결국 JPA 구현체인 Hibernate 등이 EntityManagerFactory를 만들게 됩니다.
public interface PersistenceProvider {
public EntityManagerFactory createEntityManagerFactory(String emName, Map map);
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map);
public void generateSchema(PersistenceUnitInfo info, Map map);
public boolean generateSchema(String persistenceUnitName, Map map);
public ProviderUtil getProviderUtil();
}
이제 Entity가 EntityManager로 관리된다는 것과, EntityManager가 만들어지는 과정을 알았는데, 그래서 Entity가 관리되면 어떻게 되는 걸까요? EntityManager에서. persist 하면 바로 DB에 저장되는 걸까요? 그렇지는 않습니다. EntityManager는 PersistenceContext (영속성 컨텍스트)라는 곳에 Entity를 임시로 저장해 두고, flush를 호출할 때 실제로 DB에 저장합니다.
이때 JPA에 @PersistenceContext가 있긴 하지만 이건 실제 PersistenceContext를 의미하는 게 아니라, DI로 EntityManager를 가져오기 위한 Annotation 일 뿐입니다.
@Repeatable(PersistenceContexts.class)
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface PersistenceContext {
String name() default "";
String unitName() default "";
PersistenceContextType type() default PersistenceContextType.TRANSACTION;
SynchronizationType synchronization() default SynchronizationType.SYNCHRONIZED;
PersistenceProperty[] properties() default {};
}
더 알아 두면 좋을 것들
여기서 중요한 건 JPA Entity들이 실제 어떤 과정을 거쳐서 DB에 저장되는가와 (생명주기), JPA를 한 번 더 추상화한 Spring Data JPA가 어떻게 돼 있는지입니다.
JPA Entity 생명주기 (Life Cycle) 이해하기
JPA Entity?JPA의 Entity는 JPA가 관리하는 DB의 TABLE과 연결된 객체를 말합니다. 이 Entity는 EntityManager를 통해서 관리되는데, EntityManager는 Entity를 DB에 바로 저장하지 않고 PersistenceContext (영속성 콘텍스
jinkpark.tistory.com
'👨💻 프로그래밍 > 📦 Backend' 카테고리의 다른 글
WebSecurityConfigurerAdapter 알아보기 (0) | 2023.05.13 |
---|---|
S3, AWS SDK 사용해서 Spring Boot로 이미지 업로드 기능 구현하기 (0) | 2023.05.11 |
Spring Security로 OAuth2 적용하기 (0) | 2023.05.07 |
안 하느니 못 한 "확장성을 고려한 설계" (0) | 2023.05.04 |
Spring Cloud Config로 Config 서버 구성하기 (0) | 2023.05.02 |