Überblick über Spring Data JPA
Spring Data JPA ist Teil der Spring Data Familie. Spring Data erleichtert die Erstellung von Spring-basierten Anwendungen, die neue Datenzugriffsmethoden verwenden, wie z.B. nicht-relationale Datenbanken, Map-Reduce-Frameworks, Cloud-Dienste sowie fortgeschrittene Unterstützung für relationale Datenbanken. Dieser Artikel wird sich mit Spring Data JPA befassen. Wir werden auch eine Beispielanwendung von Spring Data JPA betrachten.
Funktionen
Einige der coolen Funktionen, die von Spring Data JPA bereitgestellt werden, sind:
- Erstellen und Unterstützen von Repositories, die mit Spring und JPA erstellt wurden
- Unterstützung für QueryDSL und JPA-Abfragen
- Audit von Domänenklassen
- Unterstützung für Batch-Loading, Sortierung, dynamische Abfragen
- Unterstützt XML-Mapping für Entitäten
- Verringert die Codegröße für generische CRUD-Operationen durch die Verwendung von CrudRepository
Wann es zu verwenden?
Ich würde sagen, dass es eine gute Wahl ist, wenn Sie schnell eine auf JPA basierende Repository-Schicht erstellen müssen, die hauptsächlich für CRUD-Operationen gedacht ist und Sie keine abstrakten DAOs erstellen möchten, die Interfaces implementieren, dann ist Spring Data JPA eine gute Wahl.
Beispiel
Für unser Spring Data JPA-Beispiel werden wir einen RESTful-Webdienst erstellen, der sich mit einer Postgresql-Datenbank verbindet. Wir werden grundlegende CRUD-Operationen implementieren und mit einer Stichprobendatenbank arbeiten, die wir bereits erstellt haben.
Beispiel Stichprobendaten
Verwenden Sie die folgende Abfrage, um in der Postgresql-Datenbank eine Tabelle zu erstellen und einige Testdaten hinzuzufügen.
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-Projektstruktur
Das untenstehende Bild zeigt die finale Struktur des Spring JPA-Projekts. Wir werden später im Detail auf die einzelnen Komponenten eingehen.
Abhängigkeiten
Wir müssen die folgenden Abhängigkeiten für unser Spring Data JPA-Beispielprojekt hinzufügen.
- postgresql: Postgresql Java-Treiber.
- spring-core, spring-context: Kernabhängigkeiten des Spring Frameworks.
- spring-webmvc, jackson-databind: Für Spring REST-Anwendungen.
- spring-data-jpa, hibernate-entitymanager: für Spring Data JPA und Hibernate-Unterstützung.
Unten ist der Inhalt der finalen pom.xml Build-Datei.
<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-Konfigurationsklassen
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: Diese Spring-Annotation zeigt an, dass es sich um eine Konfigurationsklasse handelt.
@EnableTransactionManagement: Diese Annotation ermöglicht es Benutzern, Transaktionsmanagement in der Anwendung zu nutzen.
@EnableJpaRepositories(„com.journaldev.spring.repository“): zeigt an, wo die Repository-Klassen vorhanden sind.
@PropertySource(„classpath:database.properties“): weist darauf hin, dass wir eine Eigenschaftsdatei in unserem Klassenpfad haben. Die Werte aus dieser Datei werden in die Umgebungsvariable injiziert. Der Inhalt der Datei „database.properties“ ist unten dargestellt.
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
Für die Nutzung von Spring Data müssen wir zuerst das DataSource-Bean konfigurieren. Dann müssen wir das LocalContainerEntityManagerFactoryBean-Bean konfigurieren. Wir benötigen dieses Bean, um die Entitäten zu steuern. In diesem Bean müssen Sie den Persistenzanbieter angeben, in unserem Fall HibernatePersistence.
Der nächste Schritt ist die Konfiguration eines Beans für das Transaktionsmanagement. In unserem Beispiel ist es JpaTransactionManager. Beachten Sie, dass ohne die Konfiguration des Transaktionsmanagers die Annotation @Transactional nicht verwendet werden kann.
Die Klassen AppInitializer und WebConfig dienen dazu, unsere Anwendung als Webanwendung ohne Verwendung der Datei web.xml zu konfigurieren.
Model-Klasse
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: Diese Annotation ermöglicht es dem Entity-Manager, diese Klasse zu verwenden und in den Kontext zu setzen.
@Table(name = „people“): verknüpft eine Klasse mit einer Tabelle in der Datenbank.
@Id: zeigt an, dass dieses Feld der Primärschlüssel ist.
@GeneratedValue(strategy = GenerationType.IDENTITY): Definiert die Strategie zur Generierung des Primärschlüssels.
@Column(name = „age“): bezeichnet eine Spalte in der Datenbank, mit der dieses Feld verknüpft wird.
Spring Data JPA-Repository
package com.journaldev.spring.repository;
import org.springframework.data.repository.CrudRepository;
import com.journaldev.spring.model.Person;
import java.util.List;
public interface PersonRepository
extends CrudRepository<Person, Long> { List findByFirstName(String firstName); }
Indem wir von CrudRepository erben, können wir viele Methoden aufrufen, ohne sie selbst implementieren zu müssen. Einige dieser Methoden sind: save, findOne, exists, findAll, count, delete, deleteAll. Wir können auch unsere eigenen Methoden definieren. Diese Methodennamen sollten spezielle Schlüsselwörter wie „find“, „order“ mit dem Namen der Variablen verwenden. Die Entwickler von Spring Data JPA haben versucht, die Mehrheit der möglichen Optionen, die Sie benötigen könnten, zu berücksichtigen. In unserem Beispiel gibt die Methode findByFirstName(String firstName) alle Einträge aus der Tabelle zurück, bei denen das Feld first_name dem firstName entspricht. Dies ist eines der wichtigsten Merkmale von Spring Data JPA, da es eine Menge Boilerplate-Code reduziert. Auch die Fehlerwahrscheinlichkeit ist geringer, da diese Spring-Methoden bereits in vielen Projekten, die sie verwenden, gut getestet sind.
Spring-Serviceklasse
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 personRepository;
@Transactional
public List getAllPersons() {
return (List) personRepository.findAll();
}
@Transactional
public List findByName(String name) {
return personRepository.findByFirstName(name);
}
@Transactional
public Person getById(Long id) {
return personRepository.findById(id).orElse(null);
}
@Transactional
public void deletePerson(Long personId) {
personRepository.deleteById(personId);
}
@Transactional
public Person addPerson(Person person) {
return personRepository.save(person);
}
@Transactional
public Person updatePerson(Person person) {
return personRepository.save(person);
}
}
Die Annotation @Transactional zeigt an, dass die Methode in einer Transaktion ausgeführt wird. Spring kümmert sich um das Transaktionsmanagement.
Spring Controller-Klasse
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 getPersonById(@PathVariable Long id) {
return personService.getById(id);
}
@RequestMapping(value = "/personByName/{name}", method = RequestMethod.GET)
public List getPersonByName(@PathVariable String name) {
return personService.findByName(name);
}
@RequestMapping(value = "/person", method = RequestMethod.GET)
public List getAllPersons() {
return personService.getAllPersons();
}
@RequestMapping(value = "/person/{id}", method = RequestMethod.DELETE)
public HttpStatus deletePerson(@PathVariable Long id) {
personService.deletePerson(id);
return HttpStatus.NO_CONTENT;
}
@RequestMapping(value = "/person", method = RequestMethod.POST)
public HttpStatus addPerson(@RequestBody Person person) {
return personService.addPerson(person) != null ? HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
}
@RequestMapping(value = "/person", method = RequestMethod.PUT)
public HttpStatus updatePerson(@RequestBody Person person) {
return personService.updatePerson(person) != null ? HttpStatus.ACCEPTED : HttpStatus.BAD_REQUEST;
}
}
Der letzte Schritt ist die Erstellung der Controller-Klasse, um unsere APIs der Außenwelt zur Verfügung zu stellen.
Spring Data JPA-Tests
Bauen und deployen Sie das Projekt einfach in Ihren bevorzugten Servlet-Container, wie Tomcat. Die folgenden Bilder zeigen die Antwort für einige der API-Aufrufe.
Spring Data JPA Alle lesen
Spring Data JPA Nach Name abrufen
Spring Data JPA Erstellen
Spring Data JPA Aktualisieren
Spring Data JPA Löschen
Das ist alles für den Leitfaden und einen ersten Überblick.