Files
2026-10-23 19:26:44 +02:00

3.5 KiB

Was eine UI-Störung im Protokoll nennen darf

Am 2026-10-21 scheiterte in Produktion jeder Schreibvorgang. Im Journal stand dazu genau eine Zeile:

UI failure 7f3a21c4 (org.h2.jdbc.JdbcSQLNonTransientConnectionException)

Mehr gab es nicht. UiErrorConfiguration protokollierte die Klasse der untersten Ursache und sonst nichts — bewusst, denn Exception-Meldungen können SQL-Werte oder Nutzertext enthalten. Die Zurückhaltung war richtig, die Auswahl zu eng: eine Klasse allein unterscheidet keine zwei Datenbankfehler voneinander.

Warum die Klasse allein nicht reicht

Die Untersuchung zu H2-Verbindungslebenszyklus musste die Ursache aus genau dieser einen Zeile rekonstruieren. Dabei trat zutage, wie viel an Information fehlte:

  • Der SQLState hilft bei H2 nicht weiter, wo man ihn vermuten würde. H2 2.4.240 vergibt für seine 90xxx-Fehler den Fehlercode selbst als SQLState. DATABASE_IS_CLOSED meldet sqlState=90098, nicht eine 08er-Verbindungsklasse. Aus der Exception-Klasse auf eine SQLState-Klasse zu schließen, führt in die Irre; der Treibercode ist die Angabe, die trennt.
  • Die Exception-Klasse fasst sehr Verschiedenes zusammen. JdbcSQLNonTransientConnectionException steht unter anderem für DATABASE_IS_CLOSED (90098), OUT_OF_MEMORY (90108), FILE_CORRUPTED_1 (90030) und DATABASE_CALLED_AT_SHUTDOWN (90121) — Zustände mit völlig verschiedenen Konsequenzen für den Betrieb.
  • Die Kette trennt, was die unterste Klasse verbirgt. Ein erschöpfter Heap erreicht die Anwendung als JdbcSQLNonTransientConnectionException mit java.lang.OutOfMemoryError darunter; ein Schreibfehler der Ablage als JdbcSQLNonTransientException über einem MVStoreException oder IOException. Nur die Kette zeigt diesen Unterschied.

Die Rekonstruktion kam damit bis zu einer Aussage über die Form der Exception und blieb dort stehen. Mit den Angaben dieser Umsetzung wäre sie eine Zuordnung gewesen.

Was die Zeile jetzt nennt

failureDetail setzt die Zeile aus der Kette der Exception-Klassen zusammen und ergänzt bei einem Datenbankfehler sqlState und errorCode des Treibers:

UI failure 7f3a21c4 (java.lang.RuntimeException <- org.jooq.exception.DataAccessException
<- org.h2.jdbc.JdbcSQLNonTransientConnectionException sqlState=90098 errorCode=90098)

Meldungen bleiben weiterhin draußen. Das war der Grund der ursprünglichen Zurückhaltung und gilt unverändert: Klassennamen, SQLState und Fehlercode sind Werte des Treibers, keine Werte aus den Daten. Die Fehlerkennung, die der Nutzer sieht, bleibt unverändert die Brücke zwischen Meldung und Protokollzeile.

Genommen wird die letzte SQLException der Kette, nicht die erste: Spring und jOOQ hüllen den Treiberfehler in eigene SQLException-Ableitungen, deren Code und Zustand nichts aussagen. Ohne Datenbankfehler in der Kette nennt die Zeile nur die Klassen.

Die Kette ist weiterhin auf sechzehn Glieder begrenzt, wie schon zuvor beim Suchen nach RecordConflict und RecordNotFound. Für die beobachteten Ketten reicht das deutlich.

Nachweise

  • FailureDetailTest: ein Datenbankfehler in der Form des Vorfalls vom 2026-10-21 nennt sqlState=90098, errorCode=90098 und beide umhüllenden Klassen, und weder die SQL-Anweisung noch die darin enthaltene Adresse erscheinen in der Zeile; wo H2 Code und Zustand auseinanderhält (ERROR_OPENING_DATABASE_1, 08000/8000), werden beide getrennt gelesen; eine Störung ohne Datenbankursache nennt nur ihre Klassen.