Start / Seminare / Java SE in der Praxis

Modul

Datenbankzugriff

7 Kapitel in diesem Modul-Video · Laufzeit

Vertonung mit synthetischer Stimme · Inhalte redaktionell verantwortet · © 2026 HECKER CONSULTING, alle Rechte vorbehalten

Transkript

Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.

Datenbankzugriff

0:00 Am Ende des letzten Moduls hatten wir eine Anwendung, die Daten aus einer fremden Schnittstelle holt, sie versteht und filtert. Und dann endet das Programm, und alles ist weg. Das ist der Punkt, an dem aus einem Skript eine Anwendung wird: Daten müssen bleiben. In diesem Modul bringen wir die Kurse in eine Datenbank. Aber wir tun noch etwas Zweites, das mindestens so wichtig ist — wir schneiden das Projekt neu.

0:24 Denn spätestens jetzt hängt sonst alles an allem, und genau das wollen wir verhindern, bevor es passiert.

Datenbankzugriff

0:31 Sieben Stationen. Zuerst der Umbau zu mehreren Maven-Modulen — der einzige Teil dieses Seminars, den Sie im Alltag selten so machen werden, weil man normalerweise gleich mehrmodulig anfängt. Dann eine Schnittstelle für die Speicherung, danach die Datenbank selbst und der Zugriff über JDBC, einmal schreibend und einmal lesend.

0:50 Zum Schluss zeigt sich, wofür der ganze Aufwand gut war: Wir testen Fachlogik, ohne dass eine Datenbank laufen muss. Und wir klären, wie man eine verborgene Umsetzung überhaupt herausgibt. Vier Ziele. Erstens ein Projekt in Module schneiden, sodass Abhängigkeiten sichtbar und beabsichtigt sind statt zufällig. Zweitens die Speicherung hinter eine Schnittstelle legen, die kein Wort über SQL verliert.

1:14 Drittens der handwerkliche Teil: mit JDBC schreiben und lesen, ohne Verbindungen liegen zu lassen — was in älterem Code eine erstaunlich häufige Ursache für merkwürdige Ausfälle ist. Und viertens der Lohn der Mühe: Fachlogik testen, ohne dass irgendwo eine Datenbank bereitstehen muss. Diese vier Punkte hängen enger zusammen, als sie zunächst aussehen.

Vom Einzelmodul zum Mehrmodulprojekt

1:35 Fangen wir mit der Struktur an. Bisher liegt aller Code in einem einzigen Maven-Modul, und das hat bislang gereicht. Jetzt kommen Datenbankzugriff und später ein Server dazu — und dann stellt sich die Frage, wer eigentlich wen kennen darf. Es lohnt sich, diese Frage zu beantworten, bevor der Code sie stillschweigend selbst beantwortet.

1:55 Ein Maven-Projekt darf aus mehreren Modulen bestehen. Es gibt dann ein Eltern-Projekt, das die gemeinsame Konfiguration hält, und darunter Module mit eigener Projektdatei und eigenem Ergebnis. Der entscheidende Satz steht am Ende: Code eines Moduls sieht ein anderes nur, wenn eine Abhängigkeit das ausdrücklich erlaubt. Das ist mehr als Ordnung — es ist eine Grenze, die der Compiler durchsetzt.

2:18 Sie können sich nicht aus Versehen darüber hinwegsetzen, und Sie können auch nicht aus Bequemlichkeit etwas benutzen, das eigentlich woanders hingehört. Grenzen, die nur in einem Dokument stehen, halten selten lange. Interessant an dieser Aufteilung ist die Fußnote: Die Abhängigkeit läuft nur in eine Richtung. Das Datenmodul kennt die Kommandozeilenanwendung nicht — und das ist kein Zufall, sondern der eigentliche Zweck der Übung.

2:43 Denn im nächsten Modul kommt ein Server dazu, der ebenfalls auf die Datenbank zugreift. Läge der Datenbankcode in der CLI, müsste der Server die CLI mitschleppen. Absurd, aber genau so entstehen solche Abhängigkeiten in echten Projekten: nicht durch eine Entscheidung, sondern dadurch, dass jemand eine Klasse gefunden hat, die gerade passte.

3:04 Diese fünf Schritte sind Handarbeit, und ich sage gleich dazu: Das machen Sie im Berufsleben selten. Normalerweise beginnt man ein Projekt gleich mehrmodulig. Wir gehen den Weg trotzdem, weil man dabei sieht, was eigentlich passiert — welche Datei welche Rolle übernimmt und wohin die Abhängigkeiten wandern. Der wichtigste Schritt ist der letzte: einmal von ganz oben bauen. Erst dann wissen Sie, ob die Struktur wirklich steht.

3:29 Und eine Warnung aus der Praxis: Nach so einem Umbau ist die Startkonfiguration in der Entwicklungsumgebung häufig weg. Kein Fehler, nur lästig. Der erste Punkt ist der konkrete Anlass: Der Server aus dem nächsten Modul braucht die Datenbank, aber nicht die Kommandozeilenanwendung. Der zweite ist der grundsätzliche: Eine Abhängigkeit, die nicht erklärt ist, existiert nicht. Das diszipliniert erstaunlich gut.

3:53 Wenn Sie etwas benutzen wollen, das woanders liegt, müssen Sie kurz innehalten und die Abhängigkeit eintragen — und in dem Moment merken Sie manchmal, dass es die falsche Richtung wäre. Dazu kommen zwei praktische Vorteile: gemeinsame Konfiguration an einer Stelle, und Maven ermittelt die Baureihenfolge selbst. Um die müssen Sie sich also nicht kümmern.

4:14 Der erste Punkt ist eine typische Verwirrung: Das Eltern-Projekt erzeugt kein eigenes Archiv mehr, es hat eine andere Verpackungsart. Wer das übersieht, sucht ein Ergebnis, das es gar nicht geben soll. Der zweite ist verlockend und falsch: Abhängigkeiten ins Eltern-Projekt schreiben, wo sie alle Module erben — dann hat plötzlich auch das Datenmodul einen HTTP-Client.

4:36 Der dritte ist der eben erwähnte: ein Modul auf ein anderes zeigen lassen, weil gerade eine Klasse passt. Und der vierte: nach dem Umbau nur in der Entwicklungsumgebung prüfen. Die ist toleranter als Maven, und das rächt sich später.

Die Repository-Abstraktion

4:51 Jetzt zum inhaltlichen Kern dieses Moduls. Bevor wir eine Zeile SQL schreiben, legen wir fest, wie der Rest der Anwendung mit der Speicherung sprechen soll. Diese Reihenfolge ist Absicht — wer mit der Technik anfängt, bekommt am Ende eine Schnittstelle, die nach Technik aussieht. Ein Repository ist eine Schnittstelle über der Speicherung. Wer sie benutzt, weiß nichts von SQL, nichts von Verbindungen, nichts von Tabellen — er kennt nur Kurse.

5:18 Der Vergleich, der ganz gut trägt: die Ausleihtheke einer Bibliothek. Sie sagen, welches Buch Sie brauchen, und bekommen es. Ob es im Keller liegt, im Magazin oder in einer Filiale, ist Ihr Problem nicht. Und dazu gehört ein zweiter Schritt, der oft übersehen wird: ein eigener Datentyp für die Domäne. Der Katalogtyp aus Modul zwei bleibt, wo er hingehört — an der fremden Schnittstelle.

5:43 Hier steckt eine Feinheit, die Records erst richtig nützlich macht: der kompakte Konstruktor. Sie schreiben keine Parameterliste, sondern nur die Prüfung — die Zuweisung erledigt Java danach selbst. Der Gewinn ist, dass es keinen Weg an dieser Prüfung vorbei gibt. Es gibt keinen zweiten Konstruktor, den jemand aus Versehen benutzt. Ein Kurs ohne Kennung oder ohne Namen kann in dieser Anwendung schlicht nicht existieren.

6:07 Solche Prüfungen an genau einer Stelle zu haben, statt sie an jeder Aufrufstelle zu wiederholen, ist einer der unterschätzten Vorteile eigener Datentypen. Zwei Methoden — mehr braucht es zunächst nicht. Achten Sie auf das, was hier nicht steht. Keine Ausnahme aus dem Datenbankumfeld in der Signatur. Kein Hinweis auf SQL, keine Verbindung, kein Ergebnisobjekt. Das ist der eigentliche Test für eine gute Abstraktion: Verrät sie, was dahinterliegt?

6:35 Wenn in der Schnittstelle eine datenbankspezifische Ausnahme stünde, müsste jeder Aufrufer sie behandeln — und wäre damit gebunden. Wir werden deshalb gleich eine eigene Ausnahme einführen. Das ist kein Formalismus, sondern die Voraussetzung dafür, dass der Austausch der Technik überhaupt möglich bleibt. Vier Gründe, und der letzte ist der, den man am ehesten unterschätzt. Der Aufrufer denkt in Kursen — das macht den Code lesbar.

7:02 Die Datenbank ist austauschbar — das braucht man seltener, als man denkt, aber wenn, dann dringend. Tests kommen ohne laufende Datenbank aus — dazu kommen wir gleich, und das ist der handfeste Alltagsnutzen. Und der vierte: zwei Datentypen statt einem. Das fühlt sich nach Doppelung an. Es ist aber die Naht, die verhindert, dass eine Änderung an der fremden Schnittstelle bis in Ihre Datenbank durchschlägt.

7:27 Eine kurze, aber lehrreiche Aufgabe. Sie haben eben eine Prüfung in den Konstruktor geschrieben. Beweisen Sie, dass sie greift. Dafür brauchen Sie eine andere Art von Zusicherung als bisher: nicht Werte vergleichen, sondern prüfen, dass ein bestimmter Aufruf tatsächlich abbricht. JUnit bietet das an. Erfolgreich sind Sie, wenn ein leerer Name und eine fehlende Kennung nachweislich zum Abbruch führen.

7:50 Und nebenbei lernen Sie das wichtigste Muster beim Testen von Fehlerfällen — das kommt in echten Projekten mindestens so oft vor wie das Prüfen von Erfolgsfällen.

H2 und JDBC

8:01 Die Schnittstelle steht. Jetzt füllen wir sie mit Leben, und dafür brauchen wir eine Datenbank. Ich verspreche Ihnen: Sie müssen nichts installieren, keinen Dienst starten und kein Passwort setzen. Wie das geht, klären wir jetzt. H2 ist eine SQL-Datenbank, die selbst in Java geschrieben ist. Sie läuft nicht als eigener Dienst, sondern als Bibliothek in Ihrer Anwendung und schreibt ihre Daten in eine Datei.

8:26 Das ist für Seminare und kleine Werkzeuge ideal. JDBC wiederum ist die Standardschnittstelle, über die Java mit jeder SQL-Datenbank spricht, für die es einen Treiber gibt — und den gibt es praktisch immer. Der Vorteil ist Unabhängigkeit: Was Sie hier lernen, gilt fast unverändert auch für Postgres oder eine andere Datenbank. Nur die Adresse und der Treiber ändern sich.

8:49 Zwei Zeilen verdienen einen zweiten Blick. Die Datenquelle ist das Objekt, das die Datenbank beschreibt und Verbindungen ausgibt. Man verwechselt sie leicht mit der Verbindung selbst — der Unterschied ist aber wesentlich: Die Datenquelle ist langlebig, die Verbindung kurzlebig. Und der letzte Eintrag ist eine Vorbereitung auf das nächste Modul. Normalerweise darf auf eine eingebettete Datenbank nur der eigene Prozess zugreifen.

9:13 Da aber bald zwei Anwendungen dieselbe Datei nutzen sollen — die Kommandozeile und der Server —, brauchen wir eine Betriebsart, die das erlaubt. Die Verbindungsangabe sieht auf den ersten Blick kryptisch aus, ist aber gut lesbar, wenn man sie in Teile zerlegt. Vorn steht, welche Datenbank angesprochen wird, dann der Dateiname als Platzhalter, danach zwei Einstellungen.

9:35 Die zweite davon ist praktisch: Beim Öffnen wird ein SQL-Skript ausgeführt, das die Tabelle anlegt, falls sie fehlt. Für ein Seminar ist das komfortabel. Für ein echtes Projekt ist es der Punkt, an dem man auf Werkzeuge umsteigt, die Änderungen am Datenbankschema versionieren — denn ein Schema wird nicht einmal angelegt, es wächst über Jahre.

9:56 Der erste Punkt lösen wir in Modul fünf: Der Dateiname steht im Code und gehört dort nicht hin. Der zweite ist der wichtigste in diesem Kapitel — die Umsetzungsklasse bleibt paketprivat, ist also von außen unsichtbar. Wer sie öffentlich macht, hat die ganze Abstraktion aufgegeben, denn dann kann jeder direkt darauf zugreifen.

10:15 Der dritte ist eine Erwartungsfrage: Eine eingebettete Datenbank ist kein Datenbankserver, und sie endet mit Ihrer Anwendung. Und der vierte betrifft das Startskript — fehlt es, merken Sie das erst zur Laufzeit, und die Meldung ist wenig hilfreich.

Schreiben mit PreparedStatement

10:30 Jetzt schreiben wir zum ersten Mal in die Datenbank. Und dabei kommt ein Thema auf, das über dieses Seminar hinausweist: wie man SQL zusammenbaut, ohne sich eine der ältesten und wirksamsten Sicherheitslücken einzuhandeln. Der Grundgedanke ist einfach und tragfähig: Das SQL steht fest, die Werte kommen getrennt davon hinein. Sie schreiben Fragezeichen als Platzhalter und füllen sie anschließend.

10:53 Damit können Eingaben nie zu Befehlen werden — sie bleiben Daten. Das ist der Kern des Schutzes gegen SQL-Injection, und es ist keine Zusatzmaßnahme, sondern einfach die richtige Art, die Schnittstelle zu benutzen. Dazu kommt ein zweiter Punkt: Wir nutzen kein reines Einfügen, sondern ein Kommando, das einen vorhandenen Datensatz aktualisiert.

11:14 Damit läuft der Import ein zweites Mal, ohne alles zu verdoppeln. Zwei Zeilen SQL, und beide sind wohlüberlegt. Das Kommando legt an oder aktualisiert, je nachdem, ob die Kennung schon existiert — im Fachjargon heißt das Upsert. Für unseren Fall ist das genau richtig, denn der Katalogabruf wird mehrfach laufen, und dieselben Kurse sollen nicht bei jedem Lauf neu entstehen.

11:37 Und die vier Fragezeichen sind das, worüber wir gerade gesprochen haben. Beachten Sie: Das SQL steht als Konstante an einer Stelle, nicht verstreut im Methodenkörper. Wer später eine Spalte ergänzt, findet dann alles an einem Ort. Die entscheidende Zeile ist die erste. Eine Datenbankverbindung ist eine Ressource, und Ressourcen muss man schließen — auch und gerade dann, wenn etwas schiefgeht.

12:02 Genau dafür gibt es diese Schreibweise: Was in den Klammern geöffnet wird, schließt sich am Ende automatisch, im Erfolgs- wie im Fehlerfall. In älterem Java-Code sehen Sie stattdessen oft verschachtelte Blöcke, in denen genau das vergessen wurde. Das Ergebnis sind Anwendungen, die nach ein paar Stunden keine Verbindungen mehr bekommen.

12:21 Der zweite Punkt hier: Die Datenbankausnahme wird in eine eigene übersetzt — die Schnittstelle bleibt sauber. Der Sicherheitsaspekt ist der bekannteste, aber es gibt vier gute Gründe. Werte bleiben Werte und können die Struktur der Anfrage nicht verändern — das ist der Schutz. Die Datenbank kann den Ausführungsplan wiederverwenden, weil das SQL sich nicht ändert — das ist Geschwindigkeit.

12:44 Und der Code bleibt lesbar, weil das SQL an einer Stelle steht statt in Stücken zwischen Zeichenketten. Wenn Sie sich nur eine Regel aus diesem Kapitel merken, dann diese: SQL wird nie durch Zusammenkleben von Zeichenketten gebaut. Nie. Auch nicht schnell mal zum Ausprobieren. Punkt eins ist die eben genannte Regel, andersherum formuliert. Punkt zwei sind die nicht geschlossenen Verbindungen — der Fehler, der stillschweigend wächst, bis nichts mehr geht.

13:12 Punkt drei ist wichtig für die Architektur: die Datenbankausnahme nach außen reichen. Das wirkt harmlos, bricht aber die Abstraktion auf, weil jeder Aufrufer plötzlich weiß, dass darunter SQL liegt. Und Punkt vier ist ein handfester Alltagsfehler: Die Platzhalter werden über Zahlen angesprochen. Verschiebt sich eine Spalte, verschieben sich die Zahlen — und die Anwendung schreibt fröhlich die falschen Werte, ohne zu meckern.

Lesen mit ResultSet

13:38 Schreiben können wir jetzt. Lesen fehlt noch — und das ist die Gegenrichtung: Aus Tabellenzeilen sollen wieder Objekte werden. Technisch ähnelt es dem Schreiben, aber es gibt zwei Details, die man kennen sollte. Eine Abfrage liefert kein fertiges Ergebnis, sondern einen Zeiger, der zeilenweise durch die Treffer läuft. Man kann sich das wie einen Cursor in einer Tabelle vorstellen: Er steht vor der ersten Zeile und rückt bei jedem Schritt eine weiter. Aus jeder Zeile bauen wir einen Kurs.

14:06 Und am Ende geben wir bewusst keine veränderliche Liste zurück, sondern eine Kopie, an der niemand mehr etwas ändern kann. Das klingt nach Vorsicht um der Vorsicht willen, verhindert aber eine Klasse von Fehlern, bei denen ein Aufrufer die Ergebnisliste umsortiert und ein anderer sich wundert. Struktur und Muster kennen Sie schon vom Schreiben — dieselbe Ressourcenverwaltung, dieselbe Übersetzung der Ausnahme. Neu ist die Schleife und der Zugriff über Spaltennummern.

14:33 Und genau da liegt die Falle, die ich eben erwähnt habe: Diese Zahlen müssen zur Tabellendefinition passen. Wer eine Spalte einfügt, muss hier nachziehen, und der Compiler warnt nicht. Manche Projekte greifen deshalb lieber über Spaltennamen zu — etwas langsamer, dafür robuster gegen Änderungen. Beides ist vertretbar; wichtig ist, dass die Entscheidung bewusst fällt und im Projekt einheitlich bleibt.

14:57 Der erste Punkt ist die veränderliche Rückgabeliste, über die wir gerade gesprochen haben. Der zweite sind die geratenen Spaltennummern. Der dritte ist eine unauffällige Ressourcenfrage: Auch das Ergebnisobjekt sollte geschlossen werden — es hängt an der Verbindung und wird deshalb leicht übersehen. Und der vierte ist ein Denkfehler, der in wachsenden Projekten teuer wird: alle Zeilen laden und dann in Java filtern, obwohl die Datenbank das viel besser kann.

15:23 Bei zwanzig Kursen merkt das niemand. Bei zwanzigtausend Datensätzen wird daraus ein Ausfall.

Testen ohne Datenbank

15:29 Und jetzt kommt der Moment, in dem sich der ganze Aufwand mit der Schnittstelle auszahlt. Wir haben Fachlogik, die Katalogkurse in Domänenkurse übersetzt. Die wollen wir prüfen — und zwar ohne dass dafür irgendwo eine Datenbank laufen muss. Der Speicher-Service übersetzt und legt ab. Die Übersetzung ist das Interessante: Aus einer Laufzeit als Text wird eine Zahl, aus einer Teiladresse eine vollständige.

15:54 Genau das wollen wir prüfen. Und weil zwischen Service und Datenbank eine Schnittstelle liegt, können wir dort im Test etwas völlig anderes einsetzen — eine winzige Umsetzung, die alles einfach in einer Liste hält. Keine Datei, keine Datenbank, kein Aufräumen danach. Das ist der praktische Gewinn der Abstraktion, über die wir zu Beginn des Moduls gesprochen haben, und er wiegt schwerer als der theoretische.

16:18 Zehn Zeilen — mehr ist es nicht. Und diese zehn Zeilen ersetzen im Test eine komplette Datenbank. Für größere Projekte gibt es dafür eigene Bibliotheken, die solche Ersatzobjekte automatisch erzeugen; Mockito ist der bekannteste Vertreter. Die lohnen sich, sobald die Schnittstellen größer werden. Für zwei Methoden ist die Handarbeit ehrlich gesagt die klarere Lösung, weil man sofort sieht, was passiert.

16:42 Wichtiger als das Werkzeug ist ohnehin die Voraussetzung: Das Ganze funktioniert nur, weil zwischen Fachlogik und Technik eine Schnittstelle steht. Vier Gründe, und sie hängen zusammen. Der Test prüft die Übersetzung, nicht die Datenbank — er misst also das, was wir wissen wollen. Er läuft in Millisekunden und braucht keine Vorbedingungen, also läuft er auch tatsächlich, bei jedem Build.

17:05 Und wenn er fehlschlägt, zeigt er auf Ihren Code und nicht auf eine Umgebung. Das ist der Unterschied zwischen einem Test, dem man glaubt, und einem, den irgendwann alle ignorieren, weil er ohnehin ständig rot ist. Tests, die von der Umgebung abhängen, erziehen ein Team zum Wegschauen. Ihre Aufgabe: Bauen Sie diesen Test. Legen Sie einen Katalogkurs an, geben Sie ihn durch den Service und prüfen Sie, was im Ersatz-Repository ankommt.

17:31 Erfolgreich sind Sie, wenn dort ein Domänenkurs liegt, bei dem die Laufzeit eine Zahl ist und die Adresse vollständig. Achten Sie beim Schreiben darauf, was Sie eigentlich prüfen: nicht, dass etwas gespeichert wurde, sondern dass es richtig übersetzt wurde. Der Unterschied klingt spitzfindig, entscheidet aber darüber, ob der Test Ihnen später beim Ändern hilft oder nur im Weg steht.

Das Repository in der CLI nutzen

17:54 Eine Frage ist noch offen, und vielleicht haben Sie sie sich schon gestellt: Wenn die Umsetzung von außen unsichtbar ist — wie kommt die Anwendung dann überhaupt an eine? Die Antwort ist elegant und in einer Zeile erzählt. Die Lösung heißt statische Fabrikmethode, und sie steht direkt auf der Schnittstelle. Das funktioniert, weil Schnittstelle und Umsetzung im selben Paket liegen — von dort aus ist die verborgene Klasse erreichbar.

18:19 Nach außen gibt die Methode aber nur den Schnittstellentyp zurück. Der Aufrufer bekommt also etwas, das speichern und lesen kann, und erfährt nie, was genau. Der Vergleich, der ganz gut passt: eine Ausgabetheke. Sie bekommen Ihre Bestellung gereicht, ohne die Küche zu sehen. Und wenn dort morgen jemand anderes kocht, merken Sie es nicht.

18:40 Oben die Fabrikmethode, unten der Aufruf — und der ist die eigentliche Pointe. Drei Zeilen in der Kommandozeilenanwendung, und keine davon verrät, dass darunter eine SQL-Datenbank arbeitet. Kein Import einer Datenbankklasse, kein Treibername, nichts. Genau daran erkennen Sie, ob eine Abstraktion trägt: Man sieht ihr am Aufrufort nicht an, was dahintersteckt.

19:02 Sollte Kursradar irgendwann auf eine andere Datenbank umziehen, ändert sich hier keine Zeile. Und das ist keine theoretische Zukunftsmusik — im letzten Modul steht dieser Wechsel als Ausbauidee tatsächlich auf der Liste. Der erste Punkt ist die Versuchung schlechthin: Die Umsetzungsklasse doch öffentlich machen, weil der Aufruf sonst nicht geht.

19:24 Wenn Sie an diesem Punkt stehen, fehlt meist eine Fabrikmethode — nicht ein Zugriffsmodifikator. Der zweite ist der Dateiname an drei Stellen, den wir in Modul fünf auflösen. Der dritte betrifft die Datenbankdatei: Sie ist Ergebnis, nicht Quelle, und gehört nicht in die Versionsverwaltung. Und der vierte ist eine Erwartung, die viele überrascht: Endet die Anwendung, endet auch die eingebettete Datenbank. Sie läuft nicht im Hintergrund weiter.

Die Daten bleiben

19:50 Ziehen wir Bilanz. Aus einem Klumpen sind drei Module mit klaren Abhängigkeiten geworden. Die Speicherung liegt hinter einer Schnittstelle, die nur von Kursen spricht. Der Zugriff nutzt Platzhalter und schließt seine Verbindungen. Und wir können Fachlogik prüfen, ohne dass eine Datenbank läuft. Das Wichtigste daran ist nicht die Datenbank — es ist die Grenze, die wir gezogen haben.

20:13 Im nächsten Modul zeigt sich, warum: Ein Server kommt dazu, greift auf dieselben Daten zu, und er wird dafür keine einzige Zeile Datenbankcode brauchen.

Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →