Datenbankdokumentation in Spring Boot mit Schemacrawler
Dokumentation ist ein Thema, dass gerne hinten angestellt wird.
Quasi "wenn noch Zeit ist".
Vergleichbar mit Tests wird Dokumentation von manchen Personen als schlecht investierte Zeit angesehen.
Erschwerend kommt hinzu, dass die Pflege aufwendig ist:
Wird die Software weiterentwickelt, so müssen oft auch Tests und Dokumentation nachgezogen werden.
Wir haben gute Erfahrungen damit gemacht, Dokumentation - wo möglich - zu generieren.
Dabei kann sowohl der Java Quellcode als Quelle dienen, als auch Ergebnisse von automatisiert ausgeführten Tests.
Auf diese Weise kann die Dokumentation nah am Quellcode mitgepflegt werden, die Wahrscheinlichkeit sinkt, dass dies nicht bedacht oder vergessen wird.
In diesem Beitrag geht es darum, auch die Dokumentation der verwendeten Datenbankschemata zu dokumentieren. Dazu werden die Werkzeuge Testcontainers, Schemacrawler und JUnit miteinander verknüpft.
Schemacrawler ( https://www.schemacrawler.com/ ) ist ein in Java geschriebenes OpenSource Werkzeug zur Analyse von Datenbanken. Dabei werden verschiedene Dialekte unterstützt, vom sehr populären PostgreSQL bis hin zum eher vereinzelt bei Banken oder Versicherungen anzutreffenden IBM DB2. Zur Ausführung kann ein Kommandozeilenwerkzeug, Plugins für Buildwerkzeuge wie Maven und Gradle oder auch ein Container eingesetzt werden.
Da wird von den Möglichkeiten von Spring Boot bzw. Spring WebMVC zur Generierung von Dokumentation in Form von ausgeführten HTTP Requests gerne Gebrauch machen, entstand der Wunsch einen analogen Ansatz auch für Schemacrawler nutzen zu können. Für derartige Integrationstests haben sich Container (wie z.B. Docker) bewährt, da diese leicht zu verteilen und betreiben sind. Als Abstraktion und zur Integration in Testframeworks bietet das Framework Testcontainers ( https://testcontainers.com/ ) sowohl für Java als auch andere Sprachen eine sehr gute Entwicklungsproduktivität.
In aktuellen Spring Boot Versionen wurde die Integration auch nochmals mit @ServiceConnection
verbessert, so dass wenig Konfigurationscode zu schreiben ist.
Das folgende Beispiel verwendet gezielt IBM DB2, um zu zeigen, dass sich auch mit weniger neuen Produkten ein modernes Entwicklungsmodell realisieren lässt.
Zunächst gilt es, die passenden Abhängigkeiten bereitzustellen.
Das sind Testcontainers, Schemacrawler und der DB2 Support von Schemacrawler.
Maven POM mit Abhängigkeiten
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>db2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>us.fatehi</groupId>
<artifactId>schemacrawler</artifactId>
<version>16.21.2</version>
</dependency>
<dependency>
<groupId>us.fatehi</groupId>
<artifactId>schemacrawler-db2</artifactId>
<version>16.21.2</version>
</dependency>
<dependency>
<groupId>com.ibm.db2</groupId>
<artifactId>jcc</artifactId>
<scope>runtime</scope>
</dependency>
Die Spring Boot Test Konfiguration für einen IBM DB2 Datenbankcontainer mit Testcontainers ist ebenfalls sehr übersichtlich.
Damit Testdaten bereitstehen werden Beispieldaten von https://github.com/lerocha/chinook-database/ verwendet.
Praktischerweise bieten Testcontainers auch direkt an, diese Daten zu importieren.
Eine Alternative dazu wäre mit einer Spring Boot Test Annotation zu arbeiten, beipielsweise @Sql({"/Chinook_Db2.sql"})
.
Das bietet sich vor allem dann an, wenn für verschiedene @Test
Methoden unterschiedliche Daten verwendet werden sollen.
@TestConfiguration(proxyBeanMethods = false)
class TestcontainersConfiguration {
@Bean
@ServiceConnection
public Db2Container db2Container() {
var container = new Db2Container();
container.acceptLicense();
container.withInitScript("Chinook_Db2.sql");
return container;
}
}
Schemacrawler selbst bietet keine Spring oder Spring Boot Integration.
Es lässt sich dennoch einfach integrieren, dabei können vorkonfigurierte DataSource
oder JdbcTemplate
Instanzen verwendet werden:
Diese sind im Test bereits passend für die Verbindung zum Docker Container, der von Testcontainers bereitgestellt wird, konfiguriert.
Mit einem kleinen Adapter für die von Schemacrawler erwarteten API könnte der Ausführungscode wie folgt aussehen:
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
void runSchemacrawler() throws Exception {
...
final String command = "schema";
try (var ds = new JdbcTemplateConnectionSource(jdbcTemplate)) {
final SchemaCrawlerExecutable executable = new SchemaCrawlerExecutable(command);
executable.setSchemaCrawlerOptions(options);
executable.setOutputOptions(outputOptions);
executable.setDataSource(ds);
executable.execute();
}
Bei der Konfiguration von Schemacrawler stehen in der Java API im Prinzip die selben Optionen zur Verfügung, die auch bei der Ausführung als Maven Plugin oder auf der Kommandozeile bereitstehen. Damit lassen sich die zu nutzenden Schemata, Tabellen, abzufragenden Daten und auch das Ausgabeformat konfigurieren.
Einige Ausgabeformate werden durch Schemacrawler dabei direkt unterstützt, so z.B. eine tabellarische Ausgabe im HTML Format.
Für andere Formate, wie ER-Diagramme als Grafik, müssen zusätzliche Werkzeuge in der Umgebung bereitstehen.
Ist als Ausgabe eine SVG Grafik gewünscht, so müssen die Graphviz
Tools ( https://graphviz.org/ ) installiert sein.
Die folgende Konfiguration bezieht sich auf die Chinook Testdaten und lässt IBM DB2 interne Tabellen aus. Als Ausgabe wird ein SVG erzeugt.
final LimitOptionsBuilder limitOptionsBuilder = LimitOptionsBuilder.builder()
.includeSchemas(new IncludeAll())
.includeTables(new RegularExpressionInclusionRule("DB2INST1\\..*"));
final LoadOptionsBuilder loadOptionsBuilder =
LoadOptionsBuilder.builder()
// Set details to be crawled, impact on time taken to crawl the schema
.withSchemaInfoLevel(SchemaInfoLevelBuilder.standard());
final SchemaCrawlerOptions options =
SchemaCrawlerOptionsBuilder.newSchemaCrawlerOptions()
.withLimitOptions(limitOptionsBuilder.toOptions())
.withLoadOptions(loadOptionsBuilder.toOptions());
// requires 'dot' /graphviz
final Path outputFile = Path.of("target/database-schema.svg");
final var outputOptions = OutputOptionsBuilder.newOutputOptions(DiagramOutputFormat.svg, outputFile);
Ein so erzeugtes ER Diagramm als SVG sieht im Ergebnis so aus:
So generierte Grafiken sind stets aktuell und passend zum Stand der Anwendung. Zusammen mit weiteren generierten Fragmenten, z.B. MockMVC Requests- und zugehörigen Antworten, OpenAPI und bereitgestellte Metriken lassen sich hochwertige Dokumentationen erstellen, die tatsächlich nützlich und leicht zu pflegen sind.
Zu den Themen Spring Boot, Spring Security und Datenbanken bzw. SQL bieten wir sowohl Schulungen, Entwicklungsunterstützung als auch Beratung an:
Auch für Ihren individuellen Bedarf bieten wir gerne angepasste Workshops, Consulting und Schulungen an.
Sprechen Sie uns unverbindlich an.