앞선 글을 통해, JPA는 엔티티 매니저를 통해서 DB와 어플리케이션 사이의 객체인 엔티티를 다루어 수정/변경/삭제등이 이루어집니다.
이 엔티티 매니저를 어떻게 설정하는지, 스프링에 의존하지 않는 순수 Java의 설정 방법과 스프링의 DI에 의존하는 2가지 방법을 통해 알아보겠습니다.
순수 Java 설정
Entity Manager Factory → Entity Manager 의 생성은 Persistence 클래스를 사용하여 구현할 수 있습니다.
1. 설정
1.1. EntityManagerFactory 생성
<?xml version="1.0" encoding="UTF-8">
<persistence xmlns="" ...>
<persistence-unit name="db명">
<properties>
<property name="javax.persistence.jdbc.url" value="..."/>
...
</properties>
</persistence-unit>
</persistence>
Persistence는 createEntityManagerFactory(String persistenceUnitName)메서드를 통해 엔티티매니저팩토리를 생성합니다.
일반적으로 데이터베이스 당 하나의 영속성 유닛을 등록하는데, 이 정보로 데이터베이스와의 연결 및 매핑하게 됩니다.
1.2. 필요한 곳에서 EntityManager 구현
EntityManagerFactory emf = Persistence.createManagerFactory("DB명");
EntityManager em = emf.createEntityManager();
2. 단점
이 방법은 동시성과 자원 비용을 모두 수동으로 관리해주어야 한다는 단점이 있습니다.
엔티티 매니저 팩토리와 엔티티 매니저는 사용한 뒤 close()를 통해 닫아주어야 합니다.
- 엔티티 매니저 팩토리는 어플리케이션 전체에서 딱 한번만 생성하고 공유해서 사용해야 합니다. (JPA 동작을 위한 기반객체생성/커넥션 풀 생성 및 생성비용이 큼) 따라서 어플리케이션 시작 시점에 엔티티 매니저 팩토리를 생성하고, 종료 시점에 close()를 호출해 닫아주어야 합니다.
- 엔티티 매니저는 동시성 이슈로 인해 여러 스레드간에 공유해선 안되기 때문에, 스레드의 트랜잭션이 끝나면 close()로 닫아주어야 합니다.
Spring Data JPA를 활용한 설정
위와 같이 엔티티 매니저를 직접 구현해줄 수도 있지만, Spring Data JPA 라이브러리를 사용하면 엔티티 매니저를 직접 관리할 필요가 없어집니다.
스프링은 자체적으로 엔티티 매니저 팩토리/엔티티 매니저를 빈으로 등록한 뒤, 필요한 곳에서 주입받아 사용할 수 있게 해줍니다.
🤔 스프링 빈으로 엔티티 매니저를 관리하면 동시성 이슈가 생기지 않을까요?
스프링 빈은 싱글톤으로 관리되어 엔티티 매니저를 주입받게 되는 경우 동시성 문제가 생길 수 있습니다.
스프링은 사실 실제 EntityManager를 주입하는 것이 아니라, 실제 EntityManager를 연결해주는 가짜 EntityManager를 주입해둡니다.
그리고 이 EntityManager를 호출하면, 현재 데이터베이스 트랜잭션과 관련된 실제 EntityManager를 호출해주기 때문에 동시성 이슈가 발생하지 않습니다.
1. 설정
1.1. Spring
1) pom.xml에 SpringDataJPA 의존성 주입
2) application.properties에 component scan정보 등록
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.spring.jpa.controller" />
</beans:beans>
3) servlet-context.xml 에 db 정보 및 엔티티매니저팩토리 bean 등록
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<context:component-scan base-package="com.spring.jpa">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="mysql.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:mysql:@127.0.0.1:...:xe"/>
<property name="username" value="springjpa"/>
<property name="password" value="springjpa"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven/>
<jpa:repositories base-package="com.spring.jpa.repository"/><!-- transactionManager라는 이름이 아니면 명시적으로 등록해주어야한다. -->
</beans>
1.2. Spring boot
1) gradle에 Spring Data JPA 의존성 주입
2) JpaConfig파일로 어노테이션기반 bean 등록
@Configuration
@EnableJpaRepositories
public class JpaConfig {
@Bean
public DataSource dataSource() { ... }
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() { ... }
private Properties jpaProperties() { ... }
}
3) application.yml에 db정보 등록
spring.datasource.url=jdbc:....
spring.datasource.username=...
...
2.2. 엔티티 매니저 주입
@Repository
public class MemberRepository {
@PersistenceContext
private EntityManager entityManager;
@Autowired
private EntityManager entityManager;
...
}
@PersistenceContext나 @Autowired 등을 통해 스프링 컨테이너가 관리하는 엔티티 매니저를 주입받을 수 있습니다.
'백엔드 Backend > JPA' 카테고리의 다른 글
Entity에 Serializable을 구현하는 이유 (0) | 2025.01.08 |
---|---|
JPA의 기초 알아보기 (0) | 2024.08.12 |
앞선 글을 통해, JPA는 엔티티 매니저를 통해서 DB와 어플리케이션 사이의 객체인 엔티티를 다루어 수정/변경/삭제등이 이루어집니다.
이 엔티티 매니저를 어떻게 설정하는지, 스프링에 의존하지 않는 순수 Java의 설정 방법과 스프링의 DI에 의존하는 2가지 방법을 통해 알아보겠습니다.
순수 Java 설정
Entity Manager Factory → Entity Manager 의 생성은 Persistence 클래스를 사용하여 구현할 수 있습니다.
1. 설정
1.1. EntityManagerFactory 생성
<?xml version="1.0" encoding="UTF-8">
<persistence xmlns="" ...>
<persistence-unit name="db명">
<properties>
<property name="javax.persistence.jdbc.url" value="..."/>
...
</properties>
</persistence-unit>
</persistence>
Persistence는 createEntityManagerFactory(String persistenceUnitName)메서드를 통해 엔티티매니저팩토리를 생성합니다.
일반적으로 데이터베이스 당 하나의 영속성 유닛을 등록하는데, 이 정보로 데이터베이스와의 연결 및 매핑하게 됩니다.
1.2. 필요한 곳에서 EntityManager 구현
EntityManagerFactory emf = Persistence.createManagerFactory("DB명");
EntityManager em = emf.createEntityManager();
2. 단점
이 방법은 동시성과 자원 비용을 모두 수동으로 관리해주어야 한다는 단점이 있습니다.
엔티티 매니저 팩토리와 엔티티 매니저는 사용한 뒤 close()를 통해 닫아주어야 합니다.
- 엔티티 매니저 팩토리는 어플리케이션 전체에서 딱 한번만 생성하고 공유해서 사용해야 합니다. (JPA 동작을 위한 기반객체생성/커넥션 풀 생성 및 생성비용이 큼) 따라서 어플리케이션 시작 시점에 엔티티 매니저 팩토리를 생성하고, 종료 시점에 close()를 호출해 닫아주어야 합니다.
- 엔티티 매니저는 동시성 이슈로 인해 여러 스레드간에 공유해선 안되기 때문에, 스레드의 트랜잭션이 끝나면 close()로 닫아주어야 합니다.
Spring Data JPA를 활용한 설정
위와 같이 엔티티 매니저를 직접 구현해줄 수도 있지만, Spring Data JPA 라이브러리를 사용하면 엔티티 매니저를 직접 관리할 필요가 없어집니다.
스프링은 자체적으로 엔티티 매니저 팩토리/엔티티 매니저를 빈으로 등록한 뒤, 필요한 곳에서 주입받아 사용할 수 있게 해줍니다.
🤔 스프링 빈으로 엔티티 매니저를 관리하면 동시성 이슈가 생기지 않을까요?
스프링 빈은 싱글톤으로 관리되어 엔티티 매니저를 주입받게 되는 경우 동시성 문제가 생길 수 있습니다.
스프링은 사실 실제 EntityManager를 주입하는 것이 아니라, 실제 EntityManager를 연결해주는 가짜 EntityManager를 주입해둡니다.
그리고 이 EntityManager를 호출하면, 현재 데이터베이스 트랜잭션과 관련된 실제 EntityManager를 호출해주기 때문에 동시성 이슈가 발생하지 않습니다.
1. 설정
1.1. Spring
1) pom.xml에 SpringDataJPA 의존성 주입
2) application.properties에 component scan정보 등록
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.spring.jpa.controller" />
</beans:beans>
3) servlet-context.xml 에 db 정보 및 엔티티매니저팩토리 bean 등록
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<context:component-scan base-package="com.spring.jpa">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="mysql.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:mysql:@127.0.0.1:...:xe"/>
<property name="username" value="springjpa"/>
<property name="password" value="springjpa"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven/>
<jpa:repositories base-package="com.spring.jpa.repository"/><!-- transactionManager라는 이름이 아니면 명시적으로 등록해주어야한다. -->
</beans>
1.2. Spring boot
1) gradle에 Spring Data JPA 의존성 주입
2) JpaConfig파일로 어노테이션기반 bean 등록
@Configuration
@EnableJpaRepositories
public class JpaConfig {
@Bean
public DataSource dataSource() { ... }
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() { ... }
private Properties jpaProperties() { ... }
}
3) application.yml에 db정보 등록
spring.datasource.url=jdbc:....
spring.datasource.username=...
...
2.2. 엔티티 매니저 주입
@Repository
public class MemberRepository {
@PersistenceContext
private EntityManager entityManager;
@Autowired
private EntityManager entityManager;
...
}
@PersistenceContext나 @Autowired 등을 통해 스프링 컨테이너가 관리하는 엔티티 매니저를 주입받을 수 있습니다.
'백엔드 Backend > JPA' 카테고리의 다른 글
Entity에 Serializable을 구현하는 이유 (0) | 2025.01.08 |
---|---|
JPA의 기초 알아보기 (0) | 2024.08.12 |