Spring Data JPA

Spring Data JPAは、Spring Dataファミリーの一部です。Spring Dataは、非リレーショナルデータベース、マップリダクションフレームワーク、クラウドサービス、および高度なリレーショナルデータベースのサポートなど、新しいデータアクセス方法を使用するSpringドリブンアプリケーションの作成を容易にします。この記事では、Spring Data JPAについて説明します。また、Spring Data JPAのサンプルアプリケーションも紹介します。

Spring Data JPA

Spring Data JPAが提供するいくつかの便利な機能には、次のものがあります:

  1. SpringとJPAで作成されたリポジトリの作成とサポート
  2. QueryDSLとJPAクエリのサポート
  3. ドメインクラスの監査
  4. バッチローディング、ソート、動的クエリのサポート
  5. エンティティのXMLマッピングのサポート
  6. CrudRepositoryを使用して汎用CRUD操作のコードサイズを削減

Spring Data JPAを使用するタイミング

I would say that if you need to quickly create a JPA-based repository layer that is mainly for CRUD operations, and you do not want to create abstract DAO, implementing interfaces, Spring Data JPA is a good choice.

Spring Data 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プロジェクトの構造を示しています。後で各コンポーネントを詳細に調査します。

Spring Data JPA Mavenの依存関係

Spring Data JPAの例プロジェクトには、以下の依存関係を追加する必要があります。

  1. postgresql: Postgresql Javaドライバー。
  2. spring-corespring-context:Spring Frameworkのコア依存関係。
  3. spring-webmvcjackson-databind:Spring RESTアプリケーションに使用します。
  4. spring-data-jpahibernate-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>

Springの設定クラス

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:このSpringアノテーションは、設定クラスであることを示します。

  • @EnableTransactionManagement:このアノテーションは、トランザクション管理をアプリケーションで使用するためのものです。

  • @EnableJpaRepositories("com.journaldev.spring.repository"):リポジトリのクラスが存在する場所を示します。

  • @PropertySource("classpath:database.properties"): クラスパスにプロパティファイルがあることを示します。このファイルからの値は環境変数に注入されます。database.propertiesファイルの内容は以下に示されています。

    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
    
  • Spring Dataを使用するためには、まずDataSourceビーンを構成する必要があります。次にLocalContainerEntityManagerFactoryBeanビーンを構成する必要があります。このビーンはエンティティを制御するために必要です。これらのビーンでは、永続性プロバイダ(この場合はHibernatePersistence)を指定する必要があります。

  • 次のステップは、トランザクション管理のためのビーンを設定することです。私たちの例では、JpaTransactionManagerです。トランザクションマネージャを設定しないと、@Transactional アノテーションを使用できません。

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"):このフィールドが関連付けられるデータベース内の列を示します。

Spring Data JPA Repository

次のステップは、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を継承することで、実装する必要なく多くのメソッドを呼び出すことができます。これらのメソッドのいくつかは次のとおりです:

  • save
  • findOne
  • exists
  • findAll
  • count
  • delete
  • deleteAll

また、独自のメソッドを定義することもできます。これらのメソッド名は、変数名とともに「find」、「order」といった特別なキーワードを使用する必要があります。Spring Data JPAの開発者は、必要な可能性のあるほとんどのオプションを考慮しようと努めています。例えば、findByFirstName(String firstName)メソッドは、first_nameフィールドがfirstNameと等しいテーブルのすべてのエントリを返します。これはSpring Data JPAの最も重要な機能の1つであり、大量の冗長なコードを削減します。また、これらのSpringメソッドは、すでに多くのプロジェクトで使用されているため、エラーの可能性が少なく、よくテストされています。

Spring Service クラス

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がトランザクション管理を担当します。

Spring Controller クラス

最後のステップは、コントローラクラスを作成して、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;
	}
}

Spring Data JPA テスト

お気に入りのサーブレットコンテナ(Tomcatなど)にプロジェクトをビルドしてデプロイしてください。以下の画像は、いくつかのAPI呼び出しのレスポンスを示しています。

Spring Data JPA 全てを読む

Spring Data JPA 名前で取得

Spring Data JPA 作成

Spring Data JPA 更新

Spring Data JPA 削除

これでSpring Data JPAの例のチュートリアルは終わりです。最終プロジェクトは以下のリンクからダウンロードできます。

Spring Data JPAの例プロジェクトのダウンロード

参照: 公式ウェブサイト

Source:
https://www.digitalocean.com/community/tutorials/spring-data-jpa