2.4.14. Performance-Optimierung durch Caching von Tabellen

Tabellen können in den Tabellenbeschreibungen folgendermaßen als cacheable markiert werden:

Beispiel 2.45. Markieren einer Tabelle als cacheable

databaseDescription.addTableDescription("TOPPING", Cacheable.Yes, "NAME");


Das Markieren von Tabellen als cacheable geschieht ausschließlich bei der Erstellung der Datenbankbeschreibung im DatabaseDescriptionCallback. Nähere Informationen hierzu finden sich in Abschnitt 2.5.2, „Implementierung der konkreten checkerberry-db-Bridge“.

Bei dem Einspielen von initialen Testdaten prüft checkerberry db für jede Tabelle, ob sie cacheable ist und ob sie bereits in die Datenbank eingespielt wurde. Wenn die Tabelle cacheable ist und noch nicht im Cache vorhanden ist, werden die Daten in die Datenbank eingespielt und der Name der Tabelle im Cache gespeichert. Ist die Tabelle bereits in Cache vorhanden, werden die zugehörigen Daten nicht in die Datenbank eingespielt.

Das Caching-Verfahren bietet dem Benutzer die Möglichkeit, statische Stammdaten nur einmal pro Testlauf in die Datenbank zu laden. Nachfolgende Tests nutzen somit dieselben Testdaten wie die vorherigen Tests.

Abbildung 2.23. Cache

Cache


Die obige Abbildung stellt die Funktionsweise des Cache-Verfahrens dar. Auf der linken Seite sind die initialen Testdaten aufgeführt, die in die Datenbank eingespielt werden sollen. In der Mitte wird der Zustand des Caches beschrieben. Der Datenbankinhalt wird auf der rechten Seite dargestellt. In dem dargestellten Beispiel sind zunächst der Cache als auch die Datenbank leer. Die ersten Testdaten enthalten einen Eintrag für die cacheable Tabelle PARAM und einen Eintrag für die nicht-cacheable Tabelle USERS. Die Daten werden in die Datenbank eingespielt und der Name der cacheable Tabelle PARAM wird in den Cache aufgenommen.

Die zweiten Testdaten enthalten die beiden cacheable Tabellen PRODUCT und PARAM und die nicht-cacheable Tabelle USERS. Beim Einspielen der Daten werden zunächst die nicht-cacheable Tabellen geleert. In diesem Beispiel bedeutet das, dass die Inhalte der Tabelle USERS gelöscht werden. Dann wird der Datensatz für die Tabelle PRODUCT in die Datenbank eingespielt und der Tabellenname wird zu dem Cache hinzugefügt. Die Daten für die Tabelle PARAM werden nicht eingespielt, da der Tabellenname bereits im Cache vorhanden ist. Der Datensatz für die Tabelle USERS wird wiederum in die Datenbank eingespielt.

Aus Performance-Gründen prüft checkerberry db lediglich die Namen der Tabellen und nicht deren Inhalt. Es kann somit vorkommen, dass die initialen Testdaten für einen Test nicht mit dem eingespielten Datenbankinhalt übereinstimmen, da cacheable Tabellen eines vorherigen Tests nicht überschrieben wurden. Um diese potentielle Fehlerquelle zu umgehen, sollten alle Tests, die den Cache nutzen, die gleichen Werte im Cache erwarten. Aus diesem Grund ist es empfehlenswert, die Werte von cacheable Tabellen in eine eigene Include-Datei auszulagern. Diese Include-Datei sollte dann von jedem Test eingebunden werden, der eine Teilmenge der cacheable Tabellen benötigt (siehe auch Abschnitt 7.2.6, „Lagere Caching-Daten in Includes aus“).

Die cacheable Tabellen sollten so gewählt sein, dass ein Großteil der Tests die gleichen Daten verwenden kann. Das Verfahren bietet sich somit insbesondere für statische Konfigurations- oder Stammdaten an.

2.4.14.1. Leeren des Cache

Die Vorteile des Caching sind schnell nachzuvollziehen, doch wie testet man unterschiedliche Ausprägungen der cacheable Tabellen? In der Regel gibt es auch für die cacheable Tabellen eine Reihe von Komponenten, die getestet werden müssen. Aus diesem Grund stellt checkerberry db eine Möglichkeit zur Verfügung, den Inhalt des Caches zu löschen.

Beispiel 2.46. Leeren des Cache

// Cache für Tabellen PROPERTIES und COUNTRIES nicht verwenden, d.h.
// entfernen dieser Tabellen aus dem Cache und für diesen Test nicht neu in
// den Cache aufnehmen.
@NoCache("PROPERTIES", "COUNTRIES")
public void testAnything() throws Exception {
  …
}


Das obige Beispiel zeigt, wie der Cache durch Angabe der Annotation @NoCache geleert werden kann. Die Annotation kann mit einer Liste von Tabellennamen oder ohne Parameter aufgerufen werden. Wenn kein Parameter angegeben wird, bezieht sich die Annotation auf den gesamten Cache.

Die Annotation bewirkt zum einen, dass die angegebenen Tabellen aus dem Cache entfernt werden. Das führt dazu, dass in der Setup-Phase die cacheable Tabellen durch die initialen Testdaten überschrieben werden. Zum anderen führt die Annotation dazu, dass die neuen Werte der cacheable Tabellen nicht in den Cache aufgenommen werden. Der Cache wird für den Test und die angegebenen Tabellen somit temporär deaktiviert.

Die Annotation ist sowohl auf Methoden- als auch auf Klassenebene anwendbar. Des Weiteren ist es möglich, das Caching zu Testzwecken global zu deaktivieren, ohne dass man eine Annotation an jede Klasse oder Methode schreiben muss (siehe Abschnitt 2.4.14.5, „Globales Deaktivieren des Cache“).

Abbildung 2.24. NoCache-Annotation

NoCache-Annotation


Die obige Abbildung stellt beispielhaft die Verwendung der NoCache-Annotation dar. Vor dem Einspielen der Testdaten enthält der Cache die Tabellen PARAM und PRODUCT. Die Datenbank enthält für die Tabellen PRODUCT, PARAM und USERS jeweils einen Eintrag. Die initialen Testdaten gehören zu einer Testmethode oder Testklasse, die über die NoCache-Annotation das Caching für die Tabelle PARAM unterbindet. Vor dem Einspielen der Testdaten wird der Tabellenname PARAM aus dem Cache entfernt. Die Datenbankinhalte der Tabellen PARAM und USERS werden gelöscht. Danach werden die initialen Testdaten eingespielt. Die Datensätze für die Tabellen PARAM und USERS werden in die Datenbank eingespielt. Die Tabelle PARAM wird dabei jedoch nicht in den Cache aufgenommen, obwohl sie als cacheable definiert ist. Der Inhalt der Tabelle PRODUCT bleibt unverändert, da diese Tabelle bereits im Cache vorhanden ist.

Abbildung 2.25. Wachsender Cache

Wachsender Cache


Das Beispiel in Abbildung 2.25, „Wachsender Cache“ zeigt, wie der Cache nach einer NoCache-Annotation wieder aufgebaut wird. Der Anfangszustand des Beispiels entspricht dem Endezustand des vorherigen Beispiels. Die initialen Testdaten enthalten jeweils einen Eintrag für die Tabellen PRODUCT, PARAM und USERS. Die Tabellen PRODUCT und PARAM sind cacheable. Vor dem Einspielen der Testdaten werden die Inhalte der Tabellen PARAM und USERS gelöscht. Danach werden die Testdaten eingespielt. Der Datensatz der Tabelle PRODUCT wird nicht in die Datenbank geschrieben, da diese Tabelle bereits im Cache vorhanden ist. Der Datensatz für die Tabelle PARAM wird hingegen in die Datenbank geschrieben. Des Weiteren wird der Tabellenname in den Cache aufgenommen. Der Datensatz der Tabelle USERS wird in die Datenbank eingespielt.

Am Anfang des Caching-Kapitels wurde bereits die potenzielle Fehlerquelle abweichender Cache-Inhalte beschrieben. Die obige Abbildung liefert ein Beispiel für dieses Problem. Die Tabelle PRODUCT ist mit dem Wert „DSL“ in der Datenbank vorhanden. Da die Tabelle im Cache vorhanden ist, werden die Daten in der Datenbank nicht überschrieben, obwohl in den initialen Testdaten der Wert „ISDN“ eingespielt werden soll.