5. Einführung in Spring Data JPA
In diesem Kapitel werden wir die folgende Architektur untersuchen:
![]() |
Wir fügen eine [JPA]-Schicht (Java Persistence API) zwischen der [DAO]-Schicht und dem JDBC-Treiber des DBMS ein. Von nun an gibt die JPA-Schicht die für das DBMS bestimmten SQL-Befehle aus. Die [DAO]-Schicht verarbeitet keine SQL-Befehle mehr, sondern nur noch Objekte, die als JPA-Entitäten bezeichnet werden und die die verschiedenen Tabellen der verwendeten Datenbank repräsentieren. Die Felder dieser Entitäten sind über Java-Annotationen eindeutig mit Tabellenspalten verknüpft. Dadurch kann die JPA-Schicht die Operationen der [DAO]-Schicht auf JPA-Entitäten in SQL übersetzen.
Spring Data ist ein Zweig von Spring, der sich auf den Datenzugriff konzentriert, unabhängig davon, ob die Daten in einem relationalen DBMS, einer NoSQL-Datenbank oder anderen Speichertypen gespeichert sind. Hier befassen wir uns ausschließlich mit RDBMS und dem Zugriff darauf über JPA. Im weiteren Verlauf werden wir gelegentlich [Spring JPA] schreiben, um eigentlich [Spring Data JPA] zu meinen. In der obigen Architektur stellt die [Spring Data]-Schicht der [DAO]-Schicht Werkzeuge zur Verwaltung von JPA-Entitäten zur Verfügung.
JPA ist eigentlich eine Spezifikation. Wir werden drei ihrer Implementierungen testen:
- Hibernate (http://hibernate.org/);
- EclipseLink (http://www.eclipse.org/eclipselink/);
- OpenJpa (http://openjpa.apache.org/);
5.1. Beispiel-01
Die Spring-Website bietet zahlreiche Tutorials für den Einstieg in Spring [http://spring.io/guides]. Wir werden eines davon nutzen, um Spring Data vorzustellen. Dazu verwenden wir die Spring Tool Suite (STS).
![]() |
- In [1] importieren wir eines der Tutorials von [spring.io/guides];
![]() |
- In [2] wählen wir das Tutorial [Accessing Data Jpa] aus, das zeigt, wie man mit Spring Data auf eine Datenbank zugreift;
- In [3] wählen wir ein von Maven konfiguriertes Projekt aus;
- In [4] ist das Tutorial in zwei Formen verfügbar: [initial], eine leere Version, die Sie gemäß dem Tutorial ausfüllen, oder [complete], die endgültige Version des Tutorials. Wir wählen Letzteres;
- In [5] können Sie das Tutorial in einem Browser anzeigen;
- In [6] das fertige Projekt.
5.1.1. Die Maven-Konfiguration des Projekts
Die Maven-Abhängigkeiten des Projekts sind in der Datei [pom.xml] konfiguriert:
<groupId>org.springframework</groupId>
<artifactId>gs-accessing-data-jpa</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
<properties>
<!-- use UTF-8 for everything -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<start-class>hello.Application</start-class>
</properties>
- Zeilen 5–9: Definieren Sie ein übergeordnetes Maven-Projekt. Dieses Projekt definiert die meisten Abhängigkeiten des Projekts. Diese können ausreichend sein, in diesem Fall werden keine zusätzlichen Abhängigkeiten hinzugefügt, oder sie können unzureichend sein, in diesem Fall werden die fehlenden Abhängigkeiten hinzugefügt;
- Zeilen 12–15: Definieren eine Abhängigkeit von [spring-boot-starter-data-jpa]. Dieses Artefakt enthält die Spring-Data-Klassen;
- Zeilen 16–19: Definieren eine Abhängigkeit vom H2-DBMS, mit dem Sie In-Memory-Datenbanken erstellen und verwalten können.
Sehen wir uns die von diesen Abhängigkeiten bereitgestellten Klassen an:
![]() | ![]() | ![]() |
Es gibt viele davon:
- Einige gehören zum Spring-Ökosystem (diejenigen, die mit „spring“ beginnen);
- andere gehören zum Hibernate-Ökosystem (hibernate, jboss), dessen JPA-Implementierung wir hier verwenden;
- wieder andere sind Testbibliotheken (junit, hamcrest);
- wieder andere sind Logging-Bibliotheken (log4j, logback, slf4j);
Wir werden sie alle behalten. Für eine Produktionsanwendung sollten nur die notwendigen beibehalten werden.
In Zeile 26 der Datei [pom.xml] finden wir die Zeile:
<start-class>hello.Application</start-class>
Diese Zeile ist mit den folgenden Zeilen verknüpft:
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Zeilen 6–9: Mit dem [spring-boot-maven-plugin] können Sie die ausführbare JAR-Datei der Anwendung generieren. In Zeile 26 der Datei [pom.xml] wird dann die ausführbare Klasse dieser JAR-Datei angegeben.
5.1.2. Die [JPA]-Schicht
Der Datenbankzugriff wird über eine [JPA]-Schicht, die Java Persistence API, abgewickelt:
![]() |
![]() |
Die Anwendung ist einfach aufgebaut und verwaltet [Customer]-Entitäten. Die [Customer]-Klasse ist Teil der [JPA]-Schicht und sieht wie folgt aus:
package hello;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;
protected Customer() {
}
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return String.format("Customer[id=%d, firstName='%s', lastName='%s']", id, firstName, lastName);
}
}
Ein Kunde hat eine ID [id], einen Vornamen [firstName] und einen Nachnamen [lastName]. Jede [Customer]-Instanz repräsentiert eine Zeile in einer Datenbanktabelle.
- Zeile 8: JPA-Annotation, die sicherstellt, dass die Persistenz von [Customer]-Instanzen (Erstellen, Lesen, Aktualisieren, Löschen) von einer JPA-Implementierung verwaltet wird. Anhand der Maven-Abhängigkeiten lässt sich erkennen, dass die JPA/Hibernate-Implementierung verwendet wird;
- Zeilen 11–12: JPA-Annotationen, die das Feld [id] mit dem Primärschlüssel der Tabelle [Customer] verknüpfen. Zeile 12 gibt an, dass die JPA-Implementierung die für das verwendete DBMS spezifische Methode zur Primärschlüsselgenerierung verwendet, in diesem Fall H2;
Es gibt keine weiteren JPA-Annotationen. Daher werden Standardwerte verwendet:
- Die Tabelle [Customer] wird nach der Klasse benannt, d. h. [Customer];
- die Spalten dieser Tabelle werden nach den Klassenfeldern benannt: [id, firstName, lastName], wobei zu beachten ist, dass bei den Spaltennamen der Groß-/Kleinschreibung keine Bedeutung zukommt;
Beachten Sie, dass die verwendete JPA-Implementierung niemals benannt wird.
5.1.3. Die [Spring Data]-Schicht
Die Klasse [CustomerRepository] implementiert die Zugriffsebene für die Tabelle [Customer]. Ihr Code lautet wie folgt:
![]() |
![]() |
package hello;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
}
Es handelt sich also um eine Schnittstelle und nicht um eine Klasse (Zeile 7). Sie erweitert die Schnittstelle [CrudRepository], eine Spring-Data-Schnittstelle (Zeile 5). Diese Schnittstelle wird durch zwei Typen parametrisiert: Der erste ist der Typ der verwalteten Elemente, hier der Typ [Customer]; der zweite ist der Typ des Primärschlüssels der verwalteten Elemente, hier ein Typ [Long]. Die Schnittstelle [CrudRepository] sieht wie folgt aus:
package org.springframework.data.repository;
import java.io.Serializable;
@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> save(Iterable<S> entities);
T findOne(ID id);
boolean exists(ID id);
Iterable<T> findAll();
Iterable<T> findAll(Iterable<ID> ids);
long count();
void delete(ID id);
void delete(T entity);
void delete(Iterable<? extends T> entities);
void deleteAll();
}
Diese Schnittstelle definiert die CRUD-Operationen (Create – Read – Update – Delete), die für einen JPA-Typ vom Typ T ausgeführt werden können:
- Zeile 8: Die Methode „save“ ermöglicht es, eine Entität T in der Datenbank zu speichern. Sie speichert die Entität unter Verwendung des Primärschlüssels, der ihr vom DBMS zugewiesen wurde. Sie ermöglicht es auch, eine durch ihren Primärschlüssel-ID identifizierte Entität T zu aktualisieren. Die Wahl zwischen diesen beiden Aktionen hängt vom Wert der Primärschlüssel-ID ab: Ist dieser null, erfolgt die Speichervorgang; andernfalls erfolgt die Aktualisierung;
- Zeile 10: wie oben, jedoch für eine Liste von Entitäten;
- Zeile 12: Die Methode `findOne` ruft eine Entität T ab, die durch ihre Primärschlüssel-ID identifiziert wird;
- Zeile 22: Mit der Methode „delete“ können Sie eine Entität T löschen, die durch ihre Primärschlüssel-ID identifiziert wird;
- Zeilen 24–28: Varianten der Methode [delete];
- Zeile 16: Die Methode [findAll] ruft alle persistierten T-Entitäten ab;
- Zeile 18: wie oben, jedoch beschränkt auf Entitäten, für die eine Liste von Identifikatoren angegeben wurde;
Kehren wir zur Schnittstelle [CustomerRepository] zurück:
package hello;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
}
- Zeile 9 ermöglicht es Ihnen, einen [Kunden] anhand seines [Nachnamens] abzurufen;
Und das war’s auch schon für die [DAO]-Schicht. Es gibt keine Implementierungsklasse für die vorherige Schnittstelle. Sie wird zur Laufzeit von [Spring Data] generiert. Die Methoden der [CrudRepository]-Schnittstelle werden automatisch implementiert. Bei den Methoden, die der [CustomerRepository]-Schnittstelle hinzugefügt wurden, kommt es darauf an. Kehren wir zur Definition von [Customer] zurück:
private long id;
private String firstName;
private String lastName;
Die Methode in Zeile 9 wird von [Spring Data] automatisch implementiert, da sie auf das Feld [lastName] (Zeile 3) von [Customer] verweist. Wenn Spring Data in der zu implementierenden Schnittstelle auf eine [findBySomething]-Methode stößt, implementiert es diese mithilfe der folgenden JPQL-Abfrage (Java Persistence Query Language):
Daher muss der Typ T ein Feld namens [something] haben. Somit ist die Methode
wird mit einem Code implementiert, der in etwa wie folgt aussieht:
return [em].createQuery("select c from Customer c where c.lastName=:value").setParameter("value",lastName).getResultList()
wobei [em] sich auf den JPA-Persistenzkontext bezieht. Dies ist nur möglich, wenn die Klasse [Customer] ein Feld namens [lastName] enthält, was der Fall ist.
Zusammenfassend lässt sich sagen, dass Spring Data es uns in einfachen Fällen ermöglicht, die [DAO]-Schicht mit einer einfachen Schnittstelle zu implementieren.
5.1.4. Die [console]-Schicht
![]() |
![]() |
Die Klasse [Application] sieht wie folgt aus:
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
CustomerRepository repository;
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
@Override
public void run(String... strings) throws Exception {
// save a couple of customers
repository.save(new Customer("Jack", "Bauer"));
repository.save(new Customer("Chloe", "O'Brian"));
repository.save(new Customer("Kim", "Bauer"));
repository.save(new Customer("David", "Palmer"));
repository.save(new Customer("Michelle", "Dessler"));
// fetch all customers
System.out.println("Customers found with findAll():");
System.out.println("-------------------------------");
for (Customer customer : repository.findAll()) {
System.out.println(customer);
}
System.out.println();
// fetch an individual customer by ID
Customer customer = repository.findOne(1L);
System.out.println("Customer found with findOne(1L):");
System.out.println("--------------------------------");
System.out.println(customer);
System.out.println();
// fetch customers by last name
System.out.println("Customer found with findByLastName('Bauer'):");
System.out.println("--------------------------------------------");
for (Customer bauer : repository.findByLastName("Bauer")) {
System.out.println(bauer);
}
}
}
- Zeile 9: Die Klasse implementiert die Schnittstelle [CommandLineRunner], bei der es sich um eine [Spring Boot]-Schnittstelle handelt (Zeile 4). Diese Schnittstelle hat nur eine Methode, nämlich die in Zeile 19;
- Zeile 8: @SpringBootApplication ist eine Annotation, die mehrere [Spring Boot]-Annotationen zusammenfasst:
- @Configuration: gibt an, dass es sich bei der Klasse um eine Konfigurationsklasse handelt;
- @EnableAutoConfiguration: weist [Spring Boot] an, automatisch eine Reihe von Beans basierend auf verschiedenen Eigenschaften zu erstellen, insbesondere auf den Inhalten des Klassenpfads des Projekts. Da sich die Hibernate-Bibliotheken im Klassenpfad befinden, wird die [entityManagerFactory]-Bean unter Verwendung von Hibernate implementiert. Da sich die H2-DBMS-Bibliothek im Klassenpfad befindet, wird die [dataSource]-Bean unter Verwendung von H2 implementiert. In der [dataSource]-Bean müssen wir außerdem den Benutzernamen und das Passwort definieren. Hier verwendet Spring Boot den Standard-H2-Administrator, der kein Passwort hat. Da sich die [spring-tx]-Bibliothek im Klassenpfad befindet, wird der Transaktionsmanager von Spring verwendet;
- @EnableWebMvc: wenn sich die [spring-mvc]-Bibliothek im Classpath befindet. In diesem Fall wird eine automatische Konfiguration für die Webanwendung durchgeführt;
- @ComponentScan: Teilt Spring mit, wo nach anderen Beans, Konfigurationen und Diensten gesucht werden soll. Hier wird standardmäßig in dem Paket gesucht, das die annotierte Klasse enthält, d. h. im [hello]-Paket. Somit werden die Klassen [Customer] und [CustomerRepository] gefunden. Da die erste die Annotation [@Entity] trägt, wird sie als Entität katalogisiert, die von Hibernate verwaltet wird. Da die zweite die Schnittstelle [CrudRepository] erweitert, wird sie als Spring-Bean registriert;
- Zeilen 11–12: Die [CustomerRepository]-Bean wird in den Code der Hauptklasse injiziert;
- Zeile 15: Die statische Methode [run] der Klasse [SpringApplication] aus dem Spring-Boot-Projekt wird ausgeführt. Ihr Parameter ist die Klasse, die eine Annotation [Configuration] oder [EnableAutoConfiguration] trägt. Alles zuvor Erklärte findet dann statt. Das Ergebnis ist ein Spring-Anwendungskontext, d. h. eine Reihe von Beans, die von Spring verwaltet werden;
- Zeilen 19–48: Die folgenden Operationen nutzen lediglich die Methoden der Bean, die die Schnittstelle [CustomerRepository] implementiert;
Die Konsolenausgabe lautet wie folgt:
- Zeilen 1–8: das Spring Boot-Projektlogo;
- Zeile 9: Die Klasse [hello.Application] wird ausgeführt;
- Zeile 10: [AnnotationConfigApplicationContext] ist eine Klasse, die die [ApplicationContext]-Schnittstelle von Spring implementiert. Es handelt sich um einen Bean-Container;
- Zeile 11: Die Bean [entityManagerFactory] wird mit der Klasse [LocalContainerEntityManagerFactory], einer Spring-Klasse, implementiert. Sie verwaltet die [JPA]-Schicht;
- Zeile 12: [Hibernate] erscheint. Dies ist die gewählte JPA-Implementierung;
- Zeile 19: Ein Hibernate-Dialekt ist die SQL-Variante, die mit dem DBMS verwendet werden soll. Hier gibt der Dialekt [H2Dialect] an, dass Hibernate mit dem H2-DBMS arbeiten wird;
- Zeilen 21–22: Die Datenbank wird angelegt. Die Tabelle [CUSTOMER] wird angelegt. Das bedeutet, dass Hibernate so konfiguriert wurde, dass es Tabellen aus JPA-Definitionen generiert, in diesem Fall aus der JPA-Definition der Klasse [Customer];
- Zeilen 26–30: Ergebnis der Methode [findAll] der Schnittstelle;
- Zeile 34: Ergebnis der Methode [findOne] der Schnittstelle;
- Zeilen 38–39: Ergebnisse der Methode [findByLastName];
- Zeilen 41 ff.: Protokolle aus dem Spring-Kontext.
5.1.5. Manuelle Konfiguration des Spring Data-Projekts
Wir duplizieren das vorherige Projekt in das Projekt [gs-accessing-data-jpa-02]:
![]() |
In diesem neuen Projekt werden wir uns nicht auf die von Spring Boot bereitgestellte automatische Konfiguration verlassen. Wir werden es manuell konfigurieren. Dies kann nützlich sein, wenn die Standardkonfigurationen nicht unseren Anforderungen entsprechen.
Zunächst werden wir die erforderlichen Abhängigkeiten in der Datei [pom.xml] angeben:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-accessing-data-jpa-02</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
</parent>
<dependencies>
<!-- Spring Data -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<!-- H2 Database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<!-- Tomcat JDBC -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</dependency>
</dependencies>
<properties>
<!-- use UTF-8 for everything -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
</repository>
<repository>
<id>org.jboss.repository.releases</id>
<name>JBoss Maven Release Repository</name>
<url>https://repository.jboss.org/nexus/content/repositories/releases</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
- Zeilen 10–14: das übergeordnete Maven-Projekt, dessen Bibliotheken wir verwenden werden;
- Zeilen 18–21: Spring Data für den Zugriff auf die Datenbank;
- Zeilen 23–26: die Hibernate-Implementierung der JPA-Spezifikation;
- Zeilen 28–31: das H2-DBMS;
- Zeilen 33–36: Datenbanken werden oft mit Verbindungspools verwendet, wodurch das wiederholte Öffnen und Schließen von Verbindungen vermieden wird. Hier wird die Implementierung [tomcat-jdbc] verwendet;
Im neuen Projekt bleiben die Entität [Customer] und die Schnittstelle [CustomerRepository] unverändert. Wir werden die Klasse [Application] ändern, die in zwei Klassen aufgeteilt wird:
- [Config], die als Konfigurationsklasse dient;
- [Main], die als ausführbare Klasse dient;
![]() |
Die ausführbare Klasse [Application] sieht nun wie folgt aus:
package console;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import repositories.CustomerRepository;
import config.AppConfig;
import entities.Customer;
public class Application {
public static void main(String[] args) {
// instantiation Spring context
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
CustomerRepository repository = context.getBean(CustomerRepository.class);
// save a couple of customers
repository.save(new Customer("Jack", "Bauer"));
repository.save(new Customer("Chloe", "O'Brian"));
repository.save(new Customer("Kim", "Bauer"));
repository.save(new Customer("David", "Palmer"));
repository.save(new Customer("Michelle", "Dessler"));
...
// closing context
context.close();
}
}
- Zeile 9: Die Klasse [Application] enthält keine Konfigurationsanmerkungen mehr;
- Zeilen 3–7: Beachten Sie, dass keine [Spring Boot]-Paketimporte mehr vorhanden sind;
- Zeile 12: Wir instanziieren die Spring-Beans. Wir holen uns den Spring-Kontext, der Verweise auf die erstellten Beans enthält;
- Zeile 13: Wir fordern eine Referenz auf die [CustomerRepository]-Bean an;
Die Klasse [ Config], die das Projekt konfiguriert, sieht wie folgt aus:
package config;
import javax.persistence.EntityManagerFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = { "repositories" })
@Configuration
// @ComponentScan(basePackages={"package1","package2"})
public class AppConfig {
// h2 database
@Bean
public DataSource dataSource() {
// data source TomcatJdbc
DataSource dataSource = new DataSource();
// configuration access JDBC
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:./demo");
dataSource.setUsername("sa");
dataSource.setPassword("");
// an initially open connection
dataSource.setInitialSize(1);
// result
return dataSource;
}
// the provider JPA
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(false);
hibernateJpaVendorAdapter.setGenerateDdl(true);
hibernateJpaVendorAdapter.setDatabase(Database.H2);
return hibernateJpaVendorAdapter;
}
// EntityManagerFactory
@Bean
public EntityManagerFactory entityManagerFactory(JpaVendorAdapter jpaVendorAdapter, DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(jpaVendorAdapter);
factory.setPackagesToScan("entities");
factory.setDataSource(dataSource);
factory.afterPropertiesSet();
return factory.getObject();
}
// Transaction manager
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory);
return txManager;
}
}
- Zeile 17: Die Annotation [@EnableTransactionManagement] gibt an, dass [@Transactional]-Annotationen interpretiert werden müssen. Die Methoden der [CrudRepository]-Schnittstellen tragen diese Annotationen. Sie werden daher innerhalb einer Transaktion ausgeführt;
- Zeile 18: Die Annotation [@EnableJpaRepositories] gibt die Verzeichnisse an, in denen sich die Spring Data [CrudRepository]-Schnittstellen befinden. Diese Schnittstellen werden zu Spring-Komponenten und stehen im Spring-Kontext zur Verfügung;
- Zeile 19: Die Annotation [@Configuration] macht die Klasse [Config] zu einer Spring-Konfigurationsklasse;
- Zeile 20: Die Annotation [@ComponentScan] listet die Verzeichnisse auf, in denen nach Spring-Komponenten gesucht werden soll. Spring-Komponenten sind Klassen, die mit Spring-Annotationen wie @Service, @Component, @Controller usw. versehen sind. Hier gibt es außer den in der Klasse [AppConfig] definierten keine weiteren, daher wurde die Annotation auskommentiert;
- Zeilen 24–37: Definieren Sie die Datenquelle, die H2-Datenbank. Durch die Annotation @Bean in Zeile 25 wird das von dieser Methode erstellte Objekt zu einer von Spring verwalteten Komponente. Der Methodenname kann hier beliebig gewählt werden. Er muss jedoch [dataSource] lauten, wenn die EntityManagerFactory in Zeile 51 fehlt und über die automatische Konfiguration definiert wird;
- Zeile 30: Die Datenbank erhält den Namen [demo] und wird im Projektordner angelegt;
- Zeilen 40–47: Definieren Sie die verwendete JPA-Implementierung, in diesem Fall eine Hibernate-Implementierung. Der Methodenname kann hier beliebig gewählt werden;
- Zeile 43: keine SQL-Protokolle;
- Zeile 44: Die Datenbank wird erstellt, falls sie nicht existiert;
- Zeilen 50–58: Definieren die EntityManagerFactory, die die JPA-Persistenz verwaltet. Die Methode muss den Namen [entityManagerFactory] tragen;
- Zeile 51: Die Methode erhält zwei Parameter der Typen der beiden zuvor definierten Beans. Diese werden dann von Spring als Methodenparameter konstruiert und injiziert;
- Zeile 53: Legt die zu verwendende JPA-Implementierung fest;
- Zeile 54: gibt die Verzeichnisse an, in denen die JPA-Entitäten zu finden sind;
- Zeile 55: Legt die zu verwaltende Datenquelle fest;
- Zeilen 61–66: der Transaktionsmanager. Die Methode muss den Namen [transactionManager] tragen. Sie erhält die Bean aus den Zeilen 51–58 als Parameter;
- Zeile 64: Der Transaktionsmanager wird mit der EntityManagerFactory verknüpft;
Die vorangehenden Methoden können in beliebiger Reihenfolge definiert werden.
Die Ausführung des Projekts liefert die gleichen Ergebnisse. Im Projektordner erscheint eine neue Datei, die H2-Datenbankdatei:
![]() |
5.1.6. Erstellen eines ausführbaren Archivs
Um ein ausführbares Archiv des Projekts zu erstellen, gehen Sie wie folgt vor:
![]() |
- in [1]: Erstellen Sie eine Laufzeitkonfiguration;
- in [2]: vom Typ [Java-Anwendung]
- in [3]: Geben Sie das auszuführende Projekt an (verwenden Sie die Schaltfläche „Durchsuchen“);
- in [4]: Geben Sie die auszuführende Klasse an;
- in [5]: den Namen der Ausführungskonfiguration – kann beliebig sein;
![]() |
- in [6]: das Projekt exportieren;
- in [7]: als ausführbares JAR-Archiv;
- in [8]: Geben Sie den Pfad und den Namen der zu erstellenden ausführbaren Datei an;
- in [9]: den Namen der in [5] erstellten Ausführungskonfiguration;
10 ![]() |
- in [10], das erstellte Archiv;
Sobald dies erledigt ist, öffnen Sie eine Konsole in dem Ordner, der das ausführbare Archiv enthält:
Das Archiv wird wie folgt ausgeführt:
.....\dist>java -jar gs-accessing-data-jpa-02.jar
Die in der Konsole angezeigten Ergebnisse lauten wie folgt:
5.1.7. Erstellen eines [Spring Data]-Projekts
Um eine Spring Data-Projektvorlage zu erstellen, gehen Sie wie folgt vor:
![]() |
- Erstellen Sie in [1] ein neues Projekt;
- Wählen Sie unter [2] die Option [Spring Starter Project] aus;
- Das generierte Projekt ist ein Maven-Projekt. Geben Sie in [3] den Namen der Projektgruppe an;
- Geben Sie in [4] den Namen des Artefakts (hier eine JAR-Datei) an, das beim Erstellen des Projekts generiert wird;
- in [5]: den Eclipse-Namen des Projekts – dieser kann beliebig sein (muss nicht mit [4] übereinstimmen);
- in [7]: Geben Sie an, dass Sie ein Projekt mit einer [JPA]-Schicht unter Verwendung des MySQL-DBMS erstellen. Die für ein solches Projekt erforderlichen Abhängigkeiten werden dann in die Datei [pom.xml] aufgenommen;
![]() |
- in [8] den Namen des Projektordners eingeben;
- Beenden Sie in [9] den Assistenten;
![]() |
- in [10]: das erstellte Projekt;
Die Datei [pom.xml] enthält die für ein JPA-Projekt erforderlichen Abhängigkeiten:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>istia.st.springdata</groupId>
<artifactId>intro-spring-data-01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>intro-spring-data-01</name>
<description>démo spring data avec table de produits</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>demo.IntroSpringData01Application</start-class>
<java.version>1.7</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- Zeilen 14–19: das übergeordnete Maven-Projekt;
- Zeilen 28–31: die für JPA erforderliche Abhängigkeit – enthält [Spring Data];
- Zeilen 32–36: die Abhängigkeit vom MySQL-JDBC-Treiber;
- Zeilen 37–41: für JUnit-Tests erforderliche Abhängigkeiten, die in Spring integriert sind;
Die ausführbare [Application]-Klasse führt keine Aktionen aus, ist jedoch vorkonfiguriert:
package demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class IntroSpringData01Application {
public static void main(String[] args) {
SpringApplication.run(IntroSpringData01Application.class, args);
}
}
- Die Annotation [@SpringBootApplication] macht die Klasse zu einer Klasse für die automatische Projektkonfiguration;
Die Testklasse [ApplicationTests] führt keine Aktionen aus, ist jedoch vorkonfiguriert:
package demo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = IntroSpringData01Application.class)
public class IntroSpringData01ApplicationTests {
@Test
public void contextLoads() {
}
}
- Zeile 9: Die Annotation [@SpringApplicationConfiguration] ermöglicht die Verwendung der Konfigurationsdatei [IntroSpringData01Application]. Die Testklasse profitiert somit von allen in dieser Datei definierten Beans;
- Zeile 8: Die Annotation [@RunWith] ermöglicht die Integration von Spring in JUnit: Die Klasse kann als JUnit-Test ausgeführt werden. [@RunWith] ist eine JUnit-Annotation (Zeile 4), während die Klasse [SpringJUnit4ClassRunner] eine Spring-Klasse ist (Zeile 6);
Da wir nun über ein JPA-Anwendungsgerüst verfügen, können wir es vervollständigen.




















