Spring Boot | 데이터베이스 접근 | JPA 이용
JPA 이용
기본
build.gradle
dependencies {
- compile 'org.springframework.boot:spring-boot-starter-jdbc'
+ compile 'org.springframework.boot:spring-boot-starter-data-jpa'
compile 'org.hsqldb:hsqldb'
}
application.properties
spring.datasource.url=jdbc:hsqldb:file:./db/testdb;shutdown=true
spring.jpa.hibernate.ddl-auto=update
src/main/java/sample/springboot/jpa/MyEntity.java
package sample.springboot.jpa;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class MyEntity {
@Id @GeneratedValue
private Long id;
private String value;
public MyEntity(String value) {
this.value = value;
}
private MyEntity() {}
@Override
public String toString() {
return "MyEntity [id=" + id + ", value=" + value + "]";
}
}
src/main/java/sample/springboot/jpa/MyEntityRepository.java
package sample.springboot.jpa;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MyEntityRepository extends JpaRepository<MyEntity, Long> {
}
Main.java
package sample.springboot;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import sample.springboot.jpa.MyEntity;
import sample.springboot.jpa.MyEntityRepository;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
Main m = ctx.getBean(Main.class);
m.method();
}
}
@Autowired
private MyEntityRepository repository;
public void method() {
this.repository.save(new MyEntity("test"));
this.repository.findAll().forEach(System.out::println);
}
}
실행 결과
$ gradle bootRun
MyEntity [id=1, value=test]
$ gradle bootRun
MyEntity [id=1, value=test]
MyEntity [id=2, value=test]
$ gradle bootRun
MyEntity [id=1, value=test]
MyEntity [id=2, value=test]
MyEntity [id=3, value=test]
- JPA를 사용하는 경우에는
org.springframework.boot:spring-boot-starter-data-jpa
을 의존관계에 추가한다. - JPA 구현은 Hibernate가 이용된다.
- 기본으로 테이블이 매번 다시 만들게 되므로
spring.jpa.hibernate.ddl-auto=update
를 설정하고있다. - JpaRepository를 상속한 인터페이스를 정의하면 Spring이 데이터 접근을 해준다.
메소드 이름에서 쿼리 자동 생성
데이터베이스
hoge
id | number | string | value |
---|---|---|---|
1 | 1 | one | hoge |
2 | 1 | two | fuga |
3 | 1 | three | piyo |
4 | 2 | four | hoge |
5 | 2 | five | foga |
6 | 3 | six | piyo |
7 | 3 | seven | hoge |
엔티티
src/main/java/sample/springboot/jpa/Hoge.java
package sample.springboot.jpa;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Hoge {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private int number;
private String string;
@Embedded
private Fuga fuga;
@Override
public String toString() {
return "Hoge [id=" + id + ", number=" + number + ", string=" + string + ", fuga=" + fuga + "]";
}
}
src/main/java/sample/springboot/jpa/Fuga.java
package sample.springboot.jpa;
import javax.persistence.Embeddable;
@Embeddable
public class Fuga {
private String value;
@Override
public String toString() {
return "Fuga [value=" + value + "]";
}
}
저장소 인터페이스
src/main/java/sample/springboot/jpa/HogeRepository.java
package sample.springboot.jpa;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
public interface HogeRepository extends JpaRepository<Hoge, Long> {
List<Hoge> findByNumber(int number);
List<Hoge> findByNumberOrderByIdDesc(int number);
List<Hoge> findByStringLike(String string);
List<Hoge> findByNumberLessThan(int number);
List<Hoge> findByStringIgnoreCase(String string);
List<Hoge> findByFugaValue(String string);
long countByStringLike(String string);
List<Hoge> findByNumberAndStringLike(int number, String string);
List<Hoge> findByNumberOrString(int number, String string);
}
기동확인
src/main/java/sample/springboot/jpa/Main.java
package sample.springboot;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import sample.springboot.jpa.Hoge;
import sample.springboot.jpa.HogeRepository;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
Main m = ctx.getBean(Main.class);
m.method();
}
}
@Autowired
private HogeRepository repository;
public void method() {
print("findByNumber", repository.findByNumber(1));
print("findByNumberAndStringLike", repository.findByNumberAndStringLike(1, "%e"));
print("findByNumberOrString", repository.findByNumberOrString(2, "seven"));
print("findByNumberOrderByIdDesc", repository.findByNumberOrderByIdDesc(2));
print("findByStringLike", repository.findByStringLike("t%"));
print("findByNumberLessThan", repository.findByNumberLessThan(3));
print("findByStringIgnoreCase", repository.findByStringIgnoreCase("FIVE"));
print("findByFugaValue", repository.findByFugaValue("hoge"));
print("countByStringLike", repository.countByStringLike("%o%"));
}
private void print(String methodName, List<Hoge> list) {
System.out.println("<<" + methodName + ">>");
list.forEach(System.out::println);
System.out.println();
}
private void print(String methodName, long number) {
System.out.println("<<" + methodName + ">>");
System.out.println(number);
System.out.println();
}
}
실행 결과
<<findByNumber>>
Hoge [id=1, number=1, string=one, fuga=Fuga [value=hoge]]
Hoge [id=2, number=1, string=two, fuga=Fuga [value=fuga]]
Hoge [id=3, number=1, string=three, fuga=Fuga [value=piyo]]
<<findByNumberOrderByIdDesc>>
Hoge [id=5, number=2, string=five, fuga=Fuga [value=fuga]]
Hoge [id=4, number=2, string=four, fuga=Fuga [value=hoge]]
<<findByStringLike>>
Hoge [id=2, number=1, string=two, fuga=Fuga [value=fuga]]
Hoge [id=3, number=1, string=three, fuga=Fuga [value=piyo]]
<<findByNumberLessThan>>
Hoge [id=1, number=1, string=one, fuga=Fuga [value=hoge]]
Hoge [id=2, number=1, string=two, fuga=Fuga [value=fuga]]
Hoge [id=3, number=1, string=three, fuga=Fuga [value=piyo]]
Hoge [id=4, number=2, string=four, fuga=Fuga [value=hoge]]
Hoge [id=5, number=2, string=five, fuga=Fuga [value=fuga]]
<<findByStringIgnoreCase>>
Hoge [id=5, number=2, string=five, fuga=Fuga [value=fuga]]
<<findByFugaValue>>
Hoge [id=1, number=1, string=one, fuga=Fuga [value=hoge]]
Hoge [id=4, number=2, string=four, fuga=Fuga [value=hoge]]
Hoge [id=7, number=3, string=seven, fuga=Fuga [value=hoge]]
<<countByStringLike>>
3
<<findByNumberAndStringLike>>
Hoge [id=1, number=1, string=one, fuga=Fuga [value=hoge]]
Hoge [id=3, number=1, string=three, fuga=Fuga [value=piyo]]
<<findByNumberOrString>>
Hoge [id=4, number=2, string=four, fuga=Fuga [value=hoge]]
Hoge [id=5, number=2, string=five, fuga=Fuga [value=fuga]]
Hoge [id=7, number=3, string=seven, fuga=Fuga [value=hoge]]
hoge
id | number | string | value |
---|---|---|---|
1 | 1 | one | hoge |
2 | 1 | two | fuga |
3 | 1 | three | piyo |
4 | 2 | four | hoge |
5 | 2 | five | foga |
6 | 3 | six | piyo |
7 | 3 | seven | hoge |
- Repository를 상속한 인터페이스에 find~ 같은 메소드를 정의하면 Spring이 해석해서 쿼리를 자동으로 생성해 준다.
- 기본은 findBy[조건으로하는 속성의 이름]으로 정의한다.
- And와 Or로 연결이 가능하다.
- OrderBy[속성 이름][Asc|Desc]으로 정렬을 할 수 있다.
- Like를 붙이면 문자열 포함 검색 수 있다.
- LessThan, GreaterThan, Between 등도 사용할 수 있다.
- IgnoreCase를 붙이면 대소 문자 구분없이 비교할 수 있다.
- count~ 하면 검색 결과의 엔티티 수를 얻을 수 있다.
- 내장 가능 클래스의 속성을 조건으로하는 경우는 findBy[조합 가능한 클래스] [내장 가능 클래스의 속성]와 연결한다.
JPQL을 사용
src/main/java/sample/springboot/jpa/HogeRepository.java
package sample.springboot.jpa;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface HogeRepository extends JpaRepository<Hoge, Long> {
@Query("SELECT h FROM Hoge h WHERE (h.id % 2) = 0")
List<Hoge> findEvenIdEntities();
}
src/main/java/sample/springboot/Main.java
package sample.springboot;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import sample.springboot.jpa.HogeRepository;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
Main m = ctx.getBean(Main.class);
m.method();
}
}
@Autowired
private HogeRepository repository;
public void method() {
this.repository.findEvenIdEntities().forEach(System.out::println);
}
}
실행 결과
Hoge [id=2, number=1, string=two, fuga=Fuga [value=fuga]]
Hoge [id=4, number=2, string=four, fuga=Fuga [value=hoge]]
Hoge [id=6, number=3, string=six, fuga=Fuga [value=piyo]]
hoge
id | number | string | value |
---|---|---|---|
1 | 1 | one | hoge |
2 | 1 | two | fuga |
3 | 1 | three | piyo |
4 | 2 | four | hoge |
5 | 2 | five | foga |
6 | 3 | six | piyo |
7 | 3 | seven | hoge |
@Query 어노테이션을 메소드에 부여하여 JPQL을 지정할 수 있다. JPQL은 @Query의 value로 설정한다.
EntityManager을 이용
src/main/java/sample/springboot/Main.java
package sample.springboot;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import sample.springboot.jpa.Hoge;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
Main m = ctx.getBean(Main.class);
m.method();
}
}
@Autowired
private EntityManager em;
public void method() {
TypedQuery<Hoge> query = this.em.createQuery("SELECT h FROM Hoge h WHERE h.id=:id", Hoge.class);
query.setParameter("id", 3L);
Hoge hoge = query.getSingleResult();
System.out.println(hoge);
}
}
실행 결과
Hoge [id=3, number=1, string=three, fuga=Fuga [value=piyo]]
@Autowired를 사용하여 일반적으로 EntityManager를 인젝션(주입)할 수 있다.
최종 수정 : 2017-12-17