이번 포스트는 Spring Data JPA를 이용한 구현 예제를 다룬다.
JPA 관련 설정과 소스만을 다루고 이외 프로젝트 생성과 DB 설정 등은 설명하지 않는다.
Spring Boot가 아닌 Spring을 이용하여 구현한 예제이며 설정은 XML로 작성하였다.
각각의 라이브러리의 버전은 아래와 같다. (각각의 라이브러리들은 상호간의 버전이 다르면 정상적으로 동작하지 않는다. 글쓴이는 Spring 4.3.7을 기존에 사용하고 있어 아래와 같이 다른 라이브러리의 버전을 설정하였다.)
Spring : 4.3.7.RELEASE
Spring Data JPA : 1.11.1.RELEASE
Hibernate : 4.3.8.Final
구현 예제를 보이기 전, 먼저 키워드에 대한 간단한 설명을 아래와 같다.
ORM(Object-Relational Mapping)
ORM은 언어 간의 호환되지 않는 Object(객체)와 데이터베이스의 Relational(관계형) 테이블을 매핑시켜주는 프로그래밍 기법이다.
ORM을 사용하면 객체만을 이용해서 DB 테이블을 조작할 수 있도록 한다. 즉 객체를 바탕으로 SQL을 자동으로 생성해줘 쿼리를 작성하지 않아도 된다.
따라서 개발자는 쿼리가 아닌 객체 중심의 개발에만 집중할 수 있기 때문에 생산성이 높고 유지보수하기 쉽다.
JPA(Java Persistence API)
JPA는 Java에서 ORM 사용을 위하여 제공하는 인터페이스 모음이다. 즉 JPA는 기술 명세만을 표현하는 인터페이스를 제공한다.
JPA의 패키지 경로는 javax.persistence이며 실제 구현체들은 해당 패키지 아래에 있는 인터페이스들을 구현하면 된다.
해당 인터페이스를 implements 하여 직접 구현해도 되지만, 이미 해당 인터페이스를 구현하여 만들어진 프레임워크들이 존재한다.
대표적으로 Hibernate가 있으며 이외에도 DataNucleus, OpenJPA 등이 있다.
Hibernate
Hibernate는 JPA 인터페이스를 구현한 프레임워크이다.
Spring Data JPA
Spring Data JPA는 기존에 제공하는 JPA 인터페이스에 대해 한번 더 추상화한 기술이다.
Spring Data군의 포함되어 있어 일관된 Spring 기반의 프로그래밍 모델을 제공하며 좀 더 편리한 기능들을 제공하기 때문에 요즘 많이 사용하는 추세이다.
pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.11.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.8.Final</version>
</dependency>
Spring과 JPA에 사용할 spring-data-jpa와 hibernate-entitymanager를 추가한다.
applicationContext.xml
<?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:p="http://www.springframework.org/schema/p"
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.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
...
<!-- 1. JPA 구현체 밴더 빈 생성 -->
<bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<!-- 2. JAP 설정 -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="packagesToScan" value="bxi.web.jpa.entity" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
</props>
</property>
</bean>
<!-- 3. repositories 스캔 위치 -->
<jpa:repositories base-package="bxi.web.jpa.repositories" entity-manager-factory-ref="entityManagerFactory"/>
<!-- 4. 트랜잭션 설정 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
...
각각의 설정에 대한 설명은 다음과 같다.
- JPA 구현체 밴더 빈 생성
- JPA를 구현한 여러 벤더사들 중에 사용할 벤더를 설정한다.
- 이 예제는 Hibernate를 사용하므로 HibernateJpaVendorAdapter를 설정하였다.
- 이외에도 EclipseLinkJpaVendorAdapter OpenJpaVendorAdapter등이 있다.
- JPA 설정
- DB와 매핑할 객체(Entity)를 관리하는 EntityManager를 생성하는 팩토리를 설정하는 부분이다. JPA의 대한 상세 설정 부분을 담당한다.
- 사용할 dataSource를 설정한다.
- 위에서 생성한 밴더의 빈을 설정해준다.
- DB와 매핑할 객체(Entity)를 스캔할 수 있도록 Entity의 패키지 경로는 입력한다.
- jpaProperties는 JPA의 옵션들을 설정하는 부분이다. 옵션 값들은 Hibernate 문서를 참조한다.
- repositories 스캔 위치
- JPA에서 사용하는 Repositories 객체들을 스캔하는 위치이다.
- entity-manager-factory-ref는 해당 Repositories들을 사용할 EntityManager를 설정한다. EntityManager가 하나일 경우 설정하지 않아도 되지만, 여러 개일 경우는 설정해준다.
- 트랜잭션 설정
- JAP에 트랜잭션을 지원하기 위한 설정이다.
글쓴이가 가장 찾기 힘들었던 부분은 hibernate.ejb.naming_strategy 옵션이다. 해당 옵션은 Naming Strategy(네이밍 전략)를 설정하는 옵션이다. 객체의 클래스명 또는 필드명을 그대로 DB에 사용할지(객체명 : GoldUser, DB테이블명 : GOLDUSER), 아니면 CamelCase를 분석하여 대문자가 나오면 ‘_‘로 DB에 사용할지(객체명: GoldUser, DB테이블명 : GOLD_USER) 등의 네이밍 전략을 정의하는 부분이다.
대부분 블로그에서는 아래와 같이 설명하였고 이외에도 다른 방법으로 설정하는 글들이 많았지만, 글쓴이는 해당 설정이 제대로 동작하지 않았다.
// Hibernate 4
<prop key="hibernate.naming-strategy">org.hibernate.dialect.Oracle10gDialect</prop>
// Hibernate 5
<prop key="hibernate.physical_naming_strategy">org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl</prop>
<prop key="hibernate.implicit_naming_strategy">org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl</prop>