웹사이트 검색

스프링 데이터 JPA


Spring Data JPA는 Spring Data 제품군의 일부입니다. Spring Data를 사용하면 비관계형 데이터베이스, 맵 축소 프레임워크, 클라우드 서비스 및 고급 관계형 데이터베이스 지원과 같은 데이터에 액세스하는 새로운 방법을 사용하는 Spring 기반 애플리케이션을 쉽게 만들 수 있습니다. 이 기사에서는 Spring Data JPA에 대해 설명합니다. Spring Data JPA 예제 애플리케이션도 살펴보겠습니다.

스프링 데이터 JPA

Spring Data JPA에서 제공하는 멋진 기능 중 일부는 다음과 같습니다.

  1. Spring 및 JPA로 생성된 리포지토리 생성 및 지원
  2. QueryDSL 및 JPA 쿼리 지원
  3. 도메인 클래스 감사
  4. 일괄 로드, 정렬, 동적 쿼리 지원
  5. 엔터티에 대한 XML 매핑 지원
  6. CrudRepository를 사용하여 일반 CRUD 작업의 코드 크기 줄이기

Spring Data JPA를 언제 사용합니까?

주로 CRUD 작업을 위한 JPA 기반 리포지토리 레이어를 빠르게 생성해야 하고 추상 인터페이스를 생성하고 싶지 않다면 Spring Data JPA가 좋은 선택이라고 말하고 싶습니다.

스프링 데이터 JPA 예제

Spring Data JPA 예제의 경우 PostgreSQL 데이터베이스에 연결할 RESTful 웹 서비스를 생성합니다. 기본 CRUD 작업을 구현하고 이미 생성한 샘플 데이터에 대해 작업합니다.

Spring JAP 예제 샘플 데이터

아래 쿼리를 사용하여 PostgreSQL 데이터베이스에 테이블을 만들고 일부 테스트 데이터를 추가하십시오.

create table people (
id serial not null primary key,
first_name varchar(20) not null,
last_name varchar(20) not null,
age integer not null
);

insert into people (id, first_name, last_name, age) values
(1, 'Vlad', 'Boyarskiy', 21),
(2,'Oksi', ' Bahatskaya', 30),
(3,'Vadim', ' Vadimich', 32);

Spring Data JPA Maven 프로젝트 구조

Spring 데이터 JPA Maven 의존성

Spring Data JPA 예제 프로젝트에 대해 다음 종속성을 추가해야 합니다.

  1. postgresql: Postgresql 자바 드라이버.
  2. spring-core, spring-context: Spring Framework Core 의존성.
  3. spring-webmvc, jackson-databind: Spring REST 애플리케이션용.
  4. spring-data-jpa, hibernate-entitymanager: Spring Data JPA 및 Hibernate 지원용.

아래는 최종 pom.xml 빌드 파일의 내용입니다.

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.journaldev</groupId>
	<artifactId>springData</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>Spring Data JPA Maven Webapp</name>
	<url>https://maven.apache.org</url>
	<properties>
		<spring.framework>4.3.0.RELEASE</spring.framework>
		<postgres.version>42.1.4</postgres.version>
		<serializer.version>2.8.1</serializer.version>
		<spring.data>1.3.4.RELEASE</spring.data>
		<hibernate.manager>4.2.5.Final</hibernate.manager>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.framework}</version>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<version>${postgres.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.framework}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.framework}</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>${spring.data}</version>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.manager}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${serializer.version}</version>
		</dependency>
	</dependencies>

	<build>
		<finalName>${project.artifactId}</finalName>
	</build>
</project>

스프링 구성 클래스

package com.journaldev.spring.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.ejb.HibernatePersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories("com.journaldev.spring.repository")
@PropertySource("classpath:database.properties")
public class DataConfig {

	private final String PROPERTY_DRIVER = "driver";
	private final String PROPERTY_URL = "url";
	private final String PROPERTY_USERNAME = "user";
	private final String PROPERTY_PASSWORD = "password";
	private final String PROPERTY_SHOW_SQL = "hibernate.show_sql";
	private final String PROPERTY_DIALECT = "hibernate.dialect";

	@Autowired
	Environment environment;

	@Bean
	LocalContainerEntityManagerFactoryBean entityManagerFactory() {
		LocalContainerEntityManagerFactoryBean lfb = new LocalContainerEntityManagerFactoryBean();
		lfb.setDataSource(dataSource());
		lfb.setPersistenceProviderClass(HibernatePersistence.class);
		lfb.setPackagesToScan("com.journaldev.spring.model");
		lfb.setJpaProperties(hibernateProps());
		return lfb;
	}

	@Bean
	DataSource dataSource() {
		DriverManagerDataSource ds = new DriverManagerDataSource();
		ds.setUrl(environment.getProperty(PROPERTY_URL));
		ds.setUsername(environment.getProperty(PROPERTY_USERNAME));
		ds.setPassword(environment.getProperty(PROPERTY_PASSWORD));
		ds.setDriverClassName(environment.getProperty(PROPERTY_DRIVER));
		return ds;
	}

	Properties hibernateProps() {
		Properties properties = new Properties();
		properties.setProperty(PROPERTY_DIALECT, environment.getProperty(PROPERTY_DIALECT));
		properties.setProperty(PROPERTY_SHOW_SQL, environment.getProperty(PROPERTY_SHOW_SQL));
		return properties;
	}

	@Bean
	JpaTransactionManager transactionManager() {
		JpaTransactionManager transactionManager = new JpaTransactionManager();
		transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
		return transactionManager;
	}
}
  • @Configuration: this spring annotation says that it is configuration class.

  • @EnableTransactionManagement: this annotation allows users to use transaction management in application.

  • @EnableJpaRepositories("com.journaldev.spring.repository"): indicates where the repositories classes are present.

  • @PropertySource("classpath:database.properties"): says that we have property file in our classpath. The values from this file will be injected into environment variable. The contents of the database.properties file are shown below.

    driver=org.postgresql.Driver
    url=jdbc:postgresql://127.0.0.1:5432/postgres
    user=postgres
    password=postgres
    
    hibernate.dialect=org.hibernate.dialect.PostgreSQL82Dialect
    hibernate.show_sql=true
    
  • For using Spring Data, first of all we have to configure DataSource bean. Then we need to configure LocalContainerEntityManagerFactoryBean bean. We need this bean to control the entities. In this beans, you must specify the persistence provider i.e. HibernatePersistence in our case.

  • The next step is to configure bean for annotation.

AppInitializerWebConfig 클래스는 web.xml 파일을 사용하지 않고 애플리케이션을 웹 애플리케이션으로 구성하기 위한 것입니다.

모델 클래스

package com.journaldev.spring.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "people")
public class Person {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@Column(name = "age")
	private Integer age;
	@Column(name = "first_name")
	private String firstName;
	@Column(name = "last_name")
	private String lastName;

	public Person() {
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	@Override
	public String toString() {
		return "Person{" + "id=" + id + ", age=" + age + ", firstName='" + firstName + '\'' + ", lastName='" + lastName
				+ '\'' + '}';
	}
}

여기에 몇 가지 새로운 주석이 있습니다. 그들에 대해 더 자세히 이야기합시다.

  • @Entity: 이 주석은 엔티티 관리자가 이 클래스를 사용하고 컨텍스트에 넣을 수 있도록 합니다.
  • @Table(name = "people”): 클래스를 데이터베이스의 테이블과 연결합니다.
  • @Id: 이 필드가 기본 키임을 나타냅니다.
  • @GeneratedValue(strategy = GenerationType.IDENTITY): 기본 키 생성 전략을 정의합니다.
  • @Column(name = \age\): 이 필드가 연결될 데이터베이스의 열을 나타냅니다.

스프링 데이터 JPA 저장소

다음 단계는 JPA 저장소를 만드는 것입니다.

package com.journaldev.spring.repository;

import org.springframework.data.repository.CrudRepository;

import com.journaldev.spring.model.Person;

import java.util.List;

public interface PersonRepository<P> extends CrudRepository<Person, Long> {
    List<Person> findByFirstName(String firstName);
}

CrudRepository에서 상속함으로써 직접 구현할 필요 없이 많은 메서드를 호출할 수 있습니다. 이러한 방법 중 일부는 다음과 같습니다.

  • 저장
  • 파인드원
  • 있다
  • 모두 찾기
  • 카운트
  • 삭제
  • 모두 삭제

우리는 또한 우리 자신의 방법을 정의할 수 있습니다. 이러한 메서드 이름은 변수 이름과 함께 "find\, "order\와 같은 특수 키워드를 사용해야 합니다. Spring Data JPA 개발자는 필요할 수 있는 대부분의 가능한 옵션을 고려하려고 노력했습니다. 예제에서 findByFirstName(String firstName) 메서드는 first_name 필드가 firstName과 같은 테이블의 모든 항목을 반환합니다. 이는 많은 상용구 코드를 줄여주기 때문에 Spring Data JPA의 가장 중요한 기능 중 하나입니다. 또한 이러한 Spring 메소드는 이미 이를 사용하는 많은 프로젝트에서 잘 테스트되었기 때문에 오류 가능성이 적습니다.

스프링 서비스 클래스

이제 Spring Data JPA 코드가 준비되었으므로 다음 단계는 서비스 클래스를 생성하고 데이터베이스 테이블로 작업해야 하는 메서드를 정의하는 것입니다.

package com.journaldev.spring.services;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.journaldev.spring.model.Person;
import com.journaldev.spring.repository.PersonRepository;

@Service
public class PersonService {

	@Autowired
	PersonRepository<Person> personRepository;

	@Transactional
	public List<Person> getAllPersons() {
		return (List<Person>) personRepository.findAll();
	}

	@Transactional
	public List<Person> findByName(String name) {
		return personRepository.findByFirstName(name);
	}

	@Transactional
	public Person getById(Long id) {
		return personRepository.findOne(id);
	}

	@Transactional
	public void deletePerson(Long personId) {
		personRepository.delete(personId);
	}

	@Transactional
	public boolean addPerson(Person person) {
		return personRepository.save(person) != null;
	}

	@Transactional
	public boolean updatePerson(Person person) {
		return personRepository.save(person) != null;
	}
}

@Transactional 주석은 메서드가 트랜잭션에서 실행될 것임을 나타냅니다. Spring은 트랜잭션 관리를 처리합니다.

스프링 컨트롤러 클래스

마지막 단계는 API를 외부 세계에 노출하는 컨트롤러 클래스를 만드는 것입니다.

package com.journaldev.spring.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.journaldev.spring.model.Person;
import com.journaldev.spring.services.PersonService;

@RestController
public class PersonController {

	@Autowired
	PersonService personService;

	@RequestMapping(value = "/person/{id}", method = RequestMethod.GET)
	public @ResponseBody Person getAllUsers(@PathVariable Long id) {
		return personService.getById(id);
	}

	@RequestMapping(value = "/personByName/{name}", method = RequestMethod.GET)
	public List<Person> getPersoneByName(@PathVariable String name) {
		return personService.findByName(name);
	}

	@RequestMapping(value = "/person", method = RequestMethod.GET)
	public List<Person> getAll() {
		return personService.getAllPersons();
	}

	@RequestMapping(value = "/person/{id}", method = RequestMethod.DELETE)
	public HttpStatus deletePersnone(@PathVariable Long id) {
		personService.deletePerson(id);
		return HttpStatus.NO_CONTENT;
	}

	@RequestMapping(value = "/person", method = RequestMethod.POST)
	public HttpStatus insertPersone(@RequestBody Person person) {
		return personService.addPerson(person) ? HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
	}

	@RequestMapping(value = "/person", method = RequestMethod.PUT)
	public HttpStatus updatePerson(@RequestBody Person person) {
		return personService.updatePerson(person) ? HttpStatus.ACCEPTED : HttpStatus.BAD_REQUEST;
	}
}

스프링 데이터 JPA 테스트

Tomcat과 같이 선호하는 서블릿 컨테이너에 프로젝트를 빌드하고 배포하기만 하면 됩니다. 아래 이미지는 일부 API 호출에 대한 응답을 보여줍니다.

스프링 데이터 JPA 모두 읽기
스프링 데이터 JPA Get By Name
스프링 데이터 JPA 생성
스프링 데이터 JPA 업데이트
스프링 데이터 JPA 삭제

Spring Data JPA 예제 프로젝트 다운로드

참고: 공식 웹사이트