JPA 퍼시스턴스 컨텍스(JPA Persistence Context)에 접근하고 엔티티 인스턴스를 관리하려면 JPA의 핵심 인터페이스인 EntityManager를 구현한 오브젝트가 필요하다.
EntityManager는 JPA에서 두가지 방식으로 관리된다.
어떤 방식을 사용하든 반드시 EntityManagerFactory를 빈으로 등록해야한다. 스프링에서는 세 가지 방법을 이용해 EntityManagerFactory타입의 빈을 등록할 수 있다.
LocalEntityManagerFactoryBean은 JPA 스펙의 JavaSE 기동 방식을 이용해 EntityManagerFactory를 생성해준다.
<bean id="emf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
</bean>
이 빈은 PersistenceProvider 자동 감지 기능을 이용해서 프로바이더를 찾고 META-INF/persistence.xml 에 담긴 퍼시스턴스 유닛의 정보를 활용해서 EntityManagerFactory를 생성한다.
JPA는 JavaSE 환경보다는 JavaEE에서 서버가 제공하는 JPA 프로바이더를 통해 사용하는 것이 일반적.
스프링 애플리케이션에서는 JNDI를 통해 서버가 제공하는 EntityManager와 EntityManagerFactory를 제공받을 수 있다. 또 서버의 JTA를 이용해 트랜잭션 관리 기능을 활용할 수 있다.
*스프링에서는 특별히 관여할수잇는 설정은 없고, 이 방식은 JPA를 지원하는 JavaEE 5 이상의 서버에 배치하고 JPA 프로바이더와 서버가 요구하는 설정을 해뒀다고 전제한다.
모든 JPA의 기능은 서버와 JPA의 퍼시스턴스 유닛 설정(META-INF/persistence.xml)에 따른다.
스프링에서는 DAO를 사용할 수 있도록 EntityManagerFactory를 다음과 같이 JNDI 검색을 통한 빈 등록 기능을 이용해 넣으면 된다.
<jee:jndi-lookup id="emf" jndi-name="persistence/myPersistenceUnit"/>
jndi-name은 JNDI로 등록된 퍼시스턴스 유닛의 이름을 지정해주면 된다.
하지만 단지 컨테이너가 관리하는 EntityManager 방식을 사용하기 위해서라면 굳이 사용할 필요 없다.
스프링이 직접 제공해주는 컨테이너 관리 EntityManager를 사용할 수 있기 때문이다.
LocalContainerEntityManagerFactoryBean은 스프링이 직접 제공하는 컨테이너 관리 EntityManager를 위한 EntityManagerFactory를 만들어준다.
LocalContainerEntityManagerFactoryBean은 기본적으로 아래와 같이 등록해주면 된다.
필수 프로퍼티는 빈으로 등록된 dataSource를 지정해주는 것
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
이 빈은 META-INF/persistence.xml을 참고해서 퍼시스턴스 유닛과 이를 활용하는 EntityManagerFactory를 만든다. 이 때 DB연결정보는 persistence.xml에 프로퍼티로 등록하지 않아도 된다.
META-INF/persistence.xml 파일의 예시
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2.0.xsd"
version="2.0">
<persistence-unit name="default">
<class>springbook.learningtest.spring.jpa.Member</class> <!--RDB와 매핑 될 오브젝트인 엔티티 클래스들을 직접 지정가능-->
<exclude-unlisted-classes /> <!--엔티티클래스를 자동스캔않도록 지정. 이 태그 제거시 클래스에서 @Entity 애노테이션이 붙은 모든 클래스를 자동 등록한다.-->
<properties>
<property name="eclipselink.waving" value="false" /> <!--바이트코드위빙 사용 않도록 설정 -->
</properties>
</persistence-unit>
</persistence>
일부 프로퍼티 설정은 JPA 구현 제품마다 다름을 주의
자바오브젝트와 RDB 테이블 사이의 매핑과 변환을 위한 정보는 orm.xml과 같은 매핑 정보를 담은 파일에 정의하거나 애노테이션을 이용해 클래스 안에 정의 가능
@Entity
public class Member {
@Id
int id;
@Column(length=100)
String name;
@Column(nullable=false)
double point;
// 수정자(setter), 접근자(getter)
...
}
<!--persistence.xml-->
<persistence-unit name="subPersistenceUnit">
<!-- LocalContainerEntityManagerFactoryBean -->
<property name="persistenceUnitName" value="subPersistenceUnit" />
<property name="persistenceXmlLocation" value="META-INF/spring-persistence.xml" />
<!--persistence.xml-->
<persistence-unit name="default">
...
<properties>
<property name="eclipselink.waving" value="false" />
<properties>
</persistence-unit>
<!--LocalContainerEntityManagerFactoryBean-->
<property name="jpaProperties">
<props>
<prop key="eclipselink.waving">false</prop>
</props>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true" />
</bean>
</property>
JpaVendorAdapter를 이용하면 showSql뿐 아니라 매핑 DDL을 자동생성해주는 generatedDdl과 DB 종류인 database, DB 플랫폼 정보인 databasePlatform 등을 지정EntityManagerFactory 생성을 위해 제공 EntityManager 방식에는 컨테이너가 제공하는 트랜잭션 매니저가 반드시 필요<bean id="emf" class=
"org.springframework.orm.jpa.localContainerEntityManagerFactoryBean">
...
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
JpaTransactionManager를 사용하면 DataSource를 공유하는 JDBC DAO와 트랜잭션 공유 가능 (서비스 계층의 코드가 JPA DAO와 JDBC DAO를 하나의 트랜잭션 안에서 사용 가능)