Spring Data JPAは、Spring Dataファミリーの一部です。Spring Dataは、非リレーショナルデータベース、マップリダクションフレームワーク、クラウドサービス、および高度なリレーショナルデータベースのサポートなど、新しいデータアクセス方法を使用するSpringドリブンアプリケーションの作成を容易にします。この記事では、Spring Data JPAについて説明します。また、Spring Data JPAのサンプルアプリケーションも紹介します。
Spring Data JPA
Spring Data JPAが提供するいくつかの便利な機能には、次のものがあります:
- SpringとJPAで作成されたリポジトリの作成とサポート
- QueryDSLとJPAクエリのサポート
- ドメインクラスの監査
- バッチローディング、ソート、動的クエリのサポート
- エンティティのXMLマッピングのサポート
- 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の例プロジェクトには、以下の依存関係を追加する必要があります。
postgresql
: Postgresql Javaドライバー。spring-core
、spring-context
:Spring Frameworkのコア依存関係。spring-webmvc
、jackson-databind
:Spring RESTアプリケーションに使用します。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>
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
アノテーションを使用できません。
AppInitializer
とWebConfig
クラスは、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