[spring-data-jpa] 기본 예제

소개

spring-data-jpa는 jpa 기반 저장소를 쉽게 구현하도록 만들어준다. 이중에서도 눈에 띄는 특징들은

  • type-safe한 쿼리가 가능하다.
  • 공통된 저장소 기능들(CRUD)을 제공해준다.
  • @Query 어노테이션을 제공한다.

그 외에도 querydsl의 predicate 제공이나 xml 기반의 entity 매핑등의 특징들도 보인다.

예제

먼저 Spring Project로 프로젝트를 생성하고 dependency를 추가하자.

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>1.7.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>2.3.2</version>
</dependency>


스프링 프로젝트가 기본 dependency를 등록해주므로 우리는 두개만 더 등록해주자.

다음 Article.java 라는 엔티티를 만들어보자.


Article.java

package com.tistory.jekalmin.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Article {

    @Id        // primary key
    @GeneratedValue        // auto increment
    private int articleNo;
    private int memberNo;
    private String title;
    private String content;
    /* 컬럼명은 필드명이랑 동일하게 된다. 따로 명시해주고 싶으면 @Column을 사용하자 */

    /**
     * 하이버네이트가 파라미터 없는 생성자를 호출하기 때문에, 파라미터 있는 생성자를 생성했을 경우
     * 꼭 파라미터 없는 생성자를 만들어 줘야 한다.
     */
    public Article(){}

    public Article(int memberNo, String title, String content) {
        this.memberNo = memberNo;
        this.title = title;
        this.content = content;
    }

    public int getArticleNo() {
        return articleNo;
    }
    @SuppressWarnings("unused")
    private void setArticleNo(int articleNo) {
        this.articleNo = articleNo;
    }
    public int getMemberNo() {
        return memberNo;
    }
    public void setMemberNo(int memberNo) {
        this.memberNo = memberNo;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "Article [articleNo=" + articleNo + ", memberNo=" + memberNo
                + ", title=" + title + ", content=" + content + "]";
    }


}


그리고 Article 엔티티의 저장소를 만든다.


ArticleRepository.java

package com.tistory.jekalmin.repository;

import org.springframework.data.repository.CrudRepository;

import com.tistory.jekalmin.domain.Article;

public interface ArticleRepository extends CrudRepository<Article, Integer> {

}


이제 applicationContext 설정만 하면 된다.


<?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:jdbc="http://www.springframework.org/schema/jdbc"
    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/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <context:component-scan base-package="com.tistory.jekalmin"/>
    <context:annotation-config/>

    <jdbc:embedded-database id="dataSource" type="HSQL"></jdbc:embedded-database>

    <!-- spring data jpa 설정 -->

    <!-- jpa repository가 위치한 패키지 경로 등록 -->
    <jpa:repositories base-package="com.tistory.jekalmin.repository" entity-manager-factory-ref="entityManagerFactory"/>

    <!-- 하이버네이트의 SessionFactory 에 상응하는 jpa의 EntityManagerFactory 등록 -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> <!-- Hsql 형식에 맞게 변환해주는 클래스 -->
                <prop key="hibernate.connection.pool_size">1</prop>
                <prop key="hibernate.connection.shutdown">true</prop> <!-- hsql에 있는 마지막 연결이 끊어지면 데이터베이스 shutdown 하는 플래그 -->
                <prop key="hibernate.show_sql">true</prop> <!-- SQL 출력 -->
                <prop key="hibernate.hbm2ddl.auto">create</prop> <!-- 테이블 자동 생성 -->
            </props>
        </property>
        <!-- 엔티티 정의된 클래스들이 있는 패키지 등록 -->
        <property name="packagesToScan" value="com.tistory.jekalmin.domain"/>
    </bean>
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"></property>
    </bean>
    <!-- spring data jpa 설정 끝 -->



</beans>


설정 부분이 쉽지 않은데, 약간의 주석들이 도움이 되길 바란다.

이제 테스트할 클래스만 만들고 테스트하면 된다.


ArticleRepositoryTest.java

package com.tistory.jekalmin.test;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.tistory.jekalmin.domain.Article;
import com.tistory.jekalmin.repository.ArticleRepository;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring/application-config.xml")
public class ArticleRepositoryTest {

    @Resource
    ArticleRepository articleRepository;

    @Test
    public void write(){

        articleRepository.save(new Article(11, "제목", "내용"));

        System.out.println(articleRepository.findAll());

    }


}


spring-data-jpa의 가장 강력한 기능중 하나가 Repository의 기본 기능을 제공하는 것 같다. 다만 인터페이스만 선언한 만큼, 나만의 메소드를 추가하는 방법이 조금 까다롭다. 메소드를 추가하는 방법은 다음에 작성하겠다.