caffeine-library / pro-spring-5

🌱 전문가를 위한 스프링5를 읽는 스터디
5 stars 0 forks source link

[keyword] 8장 스프링에서 JPA2로 데이터 액세스하기 (1) #62

Closed emiling closed 3 years ago

emiling commented 3 years ago

주제

[8장] 스프링에서 JPA2로 데이터 액세스하기 (1) 를 읽고 중요✨ 하다고 생각하는 키워드와 선택한 이유에 대해서 코멘트로 달아주세요

연관챕터

61

binchoo commented 3 years ago

EntityManager

EntityManager영속성 컨텍스트를 관리합니다.

앱 컨텍스트가 빈을 관리하듯 영속성 컨텍스트는 엔터티 인스턴스를 관리합니다.

영속성 컨텍스트는 하이버네이트의 Session과 비슷합니다. Session은 직접 조작을 할 수 있지만 영속성 컨텍스트는 그렇지 않습니다. 대신 EntityManager를 통해야 합니다.

EntityManagerFactoryBean

EntityManagerFactory를 생성하는 팩토리 빈입니다. 영속성 유닛 정의에 기반하여 설정합니다. EntityManagerFactory는 하이버네이트의 SessionFactory와 비슷합니다.

TransactionManager

챕터9에서 자세히 설명.

구성 방법 정리

영속성 유닛과 persistence.xml

EntifyManager의 구성 정보는 영속성 유닛이라 불립니다. 앱은 여러 개의 영속성 유닛을 정의할 수 있습니다.

EntityManagerEntityManagerFactory에서 획득하고, EntityManagerFactoryEntityManagerFactoryBean에서 획득하므로 보통 팩토리 빈을 구성할 시 영속성 유닛을 알려주면 됩니다.

영속성 유닛은 META-INF/persistence.xml에 정의되는 것이 스펙입니다. 스프링3.1부터는 엔터티 스캔을 통하여 영속성 유닛을 구성하게 되어 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_1_0.xsd"
    version="1.0">

    <persistence-unit name="guestbook">
        <provider>
            oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider
        </provider>
        <class>kame.springguestbook.service.Message</class>
        <properties>
            <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="toplink.jdbc.url"
                value="jdbc:mysql://localhost/test?characterEncoding=euckr" />
            <property name="toplink.jdbc.user" value="root" />
            <property name="toplink.jdbc.password" value="root" />
        </properties>
    </persistence-unit>
</persistence>

EntityManagerFactoryBean 구성

  1. LocalEntityManagerFactoryBean 클래스 사용하기

    해당 클래스의 빈을 구성할 때 영속성 유닛의 이름을 기재하면 됩니다.

    이 클래스는DataSource 주입이 불가능하여 persistence.xml 정보만을 그대로 사용하게 됩니다.

    <bean id="entityManagerFactory"
       class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
       <property name="persistenceUnitName" value="guestbook" />
    </bean>
  2. JEE 호환 컨테이너가 제공하는 EntityMangerFactory를 사용하는 것입니다.

    호환 컨테이너에서 영속성 유닛이 부트스트랩 됨> 스프링에서 해당 객체를 룩업하여 빈 등록하도록 구성하면 됩니다.

    <beans ...>
    <jee:jndi-lookup id="prospring5Emf"
        jndi-name="persistence/prospring5PersistenceUnit" />
    </beans>
  3. LocalContainerEntityManagerFactoryBean 클래스를 사용하기

    <bean id="entityManagerFactory"
       class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       <property name="persistenceUnitName" value="guestbook" />
       <property name="dataSource" ref="dataSource" />
       <property name="jpaVendorAdapter">
           <bean class="org.springframework.orm.vendor.HibernateJpaVendorAdapter">
               <property name="database" value="MYSQL" />
           </bean>
       </property>
    </bean>

    이 클래스는 DataSource 주입이 가능합니다. 또 여러 프로퍼티 값들을 필요로 합니다.

    • persistenceUnitName persistence.xml에 정의된 영속성 유닛 이름.

      LocalContainerEntityManagerFactoryBean 빈 구성 시, DataSource와 Vendor를 설정하기 때문에 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_1_0.xsd"
       version="1.0">
      
       <persistence-unit name="guestbook" transaction-type="RESOURCE_LOCAL">
           <class>kame.spring.guestbook.service.Message</class>
       </persistence-unit>
      </persistence>
    • packagesToSacn 어노테이션이 붙은 도메인 객체를 스캔할 범위를 지정합니다. 이 방법을 채용할 경우persistence.xml에 매핑 정보가 필요 없게 되고, 아예 영속성 유닛을 정의하지 않아도 됩니다!

    • dataSource 데이터베이스 연동을 위한 DataSource

    • jpaVendorAdapter JPA API 구현체 Adapter

    • jpaProperties 영속성 제공자의 세부 설정 정보.

    • loadTimeWeaver JPA의 ClassTransformer 규약에 맞춰 클래스를 조작할 때 사용될 LoadTimeWeaver를 설정. 하이버네이트 EntityManager의 경우 : LoadTimeWeaver를 필요로 하지 않음. TopLink를 이용하는 경우 : 상황에 따라 알맞은 LoadTimeWeaver 객체를 설정 해주어야 함.

TransactionManager 구성

스프링이 제공하는 JpaTransactionManager 빈을 등록해서 사용합시다. 프로퍼티로 EntityManagerFactory를 요구합니다. 그런데 구성에는 EntityManagerFactory 빈이 없습니다. 대신 EntityManagerFactoryBean 즉, 팩토리 빈을 넘겨줘야 합니다.

어노테이션 기반 트랜잭션 경계를 활성하기 위해 <tx:annotation-drive> 태그나 @EnableTransactionManager을 선언합니다.

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManger">
    <property name="entityManagerFactory" ref="emf" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

Repository단에서 EntityManager 획득

~EntityManagerFactoryBean 팩토리 빈의 명명을 보면 이 친구가 EntityManager를 뱉어낼 것 같지만 사실 getObject() 메서드를 보면 싱글턴 EntityManagerFactory를 뱉어냅니다.

~EntityManagerFactoryBean -> EntityManagerFactory -> EntityManager -> 영속성 컨텍스트 순으로 관리되는 양상입니다. image

우리가 EntityManager를 획득하여 사용하려면 EntityManager 타입인 필드에 @PersistenceContext 어노테이션을 붙여서 주입 받아야 합니다.

영속성 유닛이 여러 개 정의되어 있다면 unitName 프로퍼티를 지정할 수 있고 @Autowired + @Qualifier 조합도 이용 가능합니다.

@Repositoy
public class SingerSerivceImple implements SingerService {
    ...
    @PersistenceContext
    private EntityManager em;

    @Transactional(readOnly=true)
    @Override
    public List<Singer> findAll() {
        return em.createNamedQuery(Singer.FIND_ALL, Singer.class).getResultList();
    }