Einstieg in Spring Boot, Teil 3 CRUD-Operationen mit Spring Data JPA

Autor / Redakteur: Dr. Dirk Koller / Stephan Augsten

In unseren Spring-Boot-Artikeln haben wir bisher nur im Code erzeugte, statische Testdaten an Views übergeben. Echte Datensätze kommen aber in der Regel aus Datenbanken. Im dritten Teil dieser Reihe realisieren wir deshalb eine Datenbankanbindung.

Firmen zum Thema

Die H2 Console erlaubt es, via Browser-Schnittstelle auf eine SQL-Datenbank zuzugreifen.
Die H2 Console erlaubt es, via Browser-Schnittstelle auf eine SQL-Datenbank zuzugreifen.
(Bild: http://h2database.com/)

Im laufenden Betrieb werden Daten meist in großen und verlässlichen Serversystemen wie Oracle, SQL Server oder MySQL abgelegt. Während der Entwicklung darf es dagegen gerne schnell und unkompliziert sein. Hier ist die H2 Database Engine eine gute Wahl.

Einbinden der H2 Database Engine

H2 lässt sich wahlweise als Serveranwendung installieren oder auch einfach als Jar über eine Maven-Abhängigkeit im Page Object Model (POM) einbinden. Neben der Angabe für die Datenbank wird dafür zusätzlich der Starter spring-boot-starter-data-jpa benötigt, der die Java Persistence API einbindet. Sie ist für das Persistieren von Java-Objekten in relationalen Datenbanken erforderlich:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
   <scope>runtime</scope>
</dependency>

Wer lieber den Assistenten der „Spring Tool Suite“ nutzen möchte, kann das natürlich auch tun: Rechtsklick auf das POM und dann Spring > Edit Starters auswählen. Die erforderlichen Abhängigkeiten heißen H2 Database und Spring Data JPA.

„Spring Boot“-Tutorial
Bildergalerie mit 20 Bildern

Steuerpult: Die H2-Konsole

Die Bedienung der Datenbank erfolgt über eine Web-Konsole, die vor der Nutzung aktiviert und konfiguriert werden muss. Das geschieht durch die beiden folgenden Einträge in der Datei application.properties unter src/main/resources:

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb

Das „mem“ in der Datasource-URL bewirkt ein Starten von H2 im In-Memory-Modus. Die Daten werden dabei nicht dauerhaft gespeichert, sie sind nach dem Schließen der Anwendung verloren. Während Test und Entwicklung ist das eine praktische Option.

Das Login-Fenster der H2-Konsole im Browser.
Das Login-Fenster der H2-Konsole im Browser.
(Bild: Dr. Koller / H2 Database Engine)

Nach dem Neustart der Anwendung steht der Login-Dialog der H2-Konsole unter „http://localhost:8080/h2-console“ zur Verfügung. Als erstes empfiehlt sich hier ein Test der Verbindung mittels Test Connection. Die JDBC-URL entspricht der in application.properties vergebenen spring.datasource.url. Der Default-User heißt sa und benötigt kein Passwort. Nach dem erfolgreichen Test loggt man sich mit Hilfe des Connect-Buttons ein und kann sich mit der Konsole vertraut machen.

Innenansicht der H2-Konsole.
Innenansicht der H2-Konsole.
(Bild: Dr. Koller / H2 Database Engine)

Im großen Textfeld rechts lassen sich Datenbankabfragen formulieren. In der Baumansicht links findet mal alle vorhandenen Datenbankobjekte. Die Tabellen im Schema INFORMATION_SCHEMA enthalten Metadaten über den Aufbau der Datenbank, die hier nicht weiter interessieren. Der User sa ist im Ordner Users zu finden. Momentan sind noch keine eigenen Datenbank-Entitäten vorhanden. Zeit das zu ändern!

Von der Klasse zur Entität

Im vorangegangenen zweiten Teil der Spring-Boot-Serie haben wie die Klasse Person angelegt, um Personen an die View zu übergeben. Die Klasse lässt sich durch geringfügige Änderungen zur Entität befördern:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Person {
   @Id
   @GeneratedValue(strategy=GenerationType.AUTO)
   private Long id;
   private String firstname;
   private String lastname;
   public Long getId() {
      return id;
   }
   public void setId(Long id) {
   this.id = id;
   }
   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;
   }
}

Die Annotation @Entity_ kennzeichnet die Klasse als Entität. Die neue Membervariable „id“ dient als Primärschlüssel in der Datenbank und wird mit @Id_ gekennzeichnet. Da der Wert von Spring automatisch vergeben werden soll, wird sie außerdem mit GeneratedValue annotiert und dabei die Strategie AUTO genutzt.

Die H2-Datenbank mit Person-Tabelle.
Die H2-Datenbank mit Person-Tabelle.
(Bild: Dr. Koller / H2 Database Engine)

Die Getter und Setter lassen sich wieder mit Source > Generate Getter and Setters in Eclipse oder der Spring Tools Suite generieren. Das war‘s, die Entität ist einsatzbereit. Nach einem Neustart findet man die entsprechende Tabelle in der Datenbank, allerdings noch ohne Inhalt.

Initialdaten mit data.sql

Zum Einfügen von initialen Datenbankinhalten bietet Spring eine einfache Möglichkeit: Insert-Statements in der Datei data.sql (beispielsweise unter src/main/ressources) werden automatisch ausgeführt. Hier werden zwei Mitglieder der Familie Mustermann in die Datenbank geschrieben:

INSERT INTO person (id, firstname, lastname) VALUES (-1, 'Max', 'Mustermann');
INSERT INTO person (id, firstname, lastname) VALUES (-2, 'Erika', 'Mustermann');

Da es sich dabei um einfache SQL-Inserts ohne Spring-Funktionalität handelt, muss der Primärschlüssel von Hand vergeben werden. Wir verwenden hier negative Werte, damit diese nicht mit den später automatisch vergebenen Primärschlüsselwerten kollidieren.

Testdaten in H2.
Testdaten in H2.
(Bild: Dr. Koller / H2 Database Engine)

In der H2-Console lassen sich die Testdaten nach dem Neustart mit einer Select-Abfrage anzeigen. Man kann dazu einfach auf die Tabelle „Person“ klicken, das Statement wird dann wie in der vorngestellten Abbildung automatisch rechts in das Textfeld eingefügt.

Für Datenbankinteraktionen existieren in Spring zwei Möglichkeiten: Zum einen das JDBC Template, eine Art Wrapper um den altgedienten JDBC-Zugriff, oder, deutlich eleganter, mit Hilfe von Spring Data Repositories. Repositories sind eine Persistenz-Abstraktion, die Zugriff auf Domain-Objekte in Form von Collections gestatten. Das Pattern ähnelt ein wenig dem bekannteren DAO-Pattern.

Die Implementierung ist recht einfach. Man erstellt zunächst ein Repository-Interface für die entsprechende Domain-Klasse, hier also Person. Das Interface erbt von einem von mehreren Standard-Interfaces, zum Beispiel dem CrudRepository, und wird mit der Domainklasse (Person) und dem Datentyp von dessen ID (Long) typisiert:

public interface PersonRepository extends CrudRepository<Person, Long>{}

CRUD steht für Create, Read, Update und Delete, also die gängigen Datenbankoperationen. Die Implementierung des Interface wird von Spring gestellt, sie beinhaltet diese Operationen. Um das auszuprobieren, lässt man sich eine Repository-Bean in einen Controller injizieren und kann dann die geerbten Methoden verwenden. Im folgenden Beispiel wird der zuvor eingefügte Testdatensatz mit findById() und dem passenden Primary Key ausgelesen:

@Controller
public class PersonController {
   @Autowired
   PersonRepository personRepository;
   @GetMapping("/")
   @ResponseBody
   public String home() {
      Optional<Person> person = personRepository.findById(-1L);
      if(person.isPresent()) {
         return person.get().getLastname();
      } else {
         return "Keine Person mit dieser Id gefunden :-(";
      }
   }
}

Die Methode findAll() findet alle Entitäten im Repository:

List<Person> persons = (List<Person>) personRepository.findAll();

Natürlich kann man auch neue Datensätze anlegen, die entsprechende Repository-Methode heißt save:

Person newPerson = new Person();
newPerson.setFirstname("Frank");
newPerson.setLastname("Mustermann");
personRepository.save(newPerson);

Testdaten mit automatisch generiertem Primärschlüssel.
Testdaten mit automatisch generiertem Primärschlüssel.
(Bild: Dr. Koller / H2 Database Engine)

Dabei wird der Primärschlüssel nun automatisch vergeben. Wie man im Screenshot sieht, startet die Nummerierung mit der Nummer Eins.

„Spring Boot“-Tutorial
Bildergalerie mit 20 Bildern

Die save-Methode kommt auch beim Update zum Einsatz. Einer vorhandenen Entität wird dabei ein anderer Attribut-Wert zugewiesen und anschließend mit save gespeichert.

Fehlt noch das Löschen. Die Methode delete(entity) löscht eine Entität mit der gegebenen Referenz. Wenn diese nicht bekannt ist, kann man mit deleteById(id) auch den Primärschlüssel als Kriterium nutzen.

Damit sind die vier CRUD-Operationen komplett. Im nächsten Teil der Artikelreihe beschäftigen wir uns mit anspruchsvolleren Datenbank-Queries in Spring Boot.

(ID:47019448)

Über den Autor