Zum Inhalt

Datenbank / Unterstützte Datenbanken

KCForms speichert seine eigenen Daten in einer relationalen Datenbank. Standard ist MySQL 8; daneben kann KCForms auch auf PostgreSQL, Oracle und Microsoft SQL Server laufen. Welche es ist, steht unter System-Administration → Schnittstellen & Verteilung → Datenquellen im Kasten Haupt-Datenbank.

Externe Datenquellen ≠ Haupt-Datenbank

Diese Seite betrifft die eigene Ablage von KCForms. Externe Datenquellen für Skripte, Lookups und Picker (db.on(...)) sind davon unabhängig und können jede der unterstützten Datenbanken sein — siehe Datenquellen.

Unterstützte Datenbanken

Datenbank Status Mindestversion (empfohlen)
MySQL Produktiv (Standard) 8.0 (getestet gegen 8.4)
PostgreSQL Betrieb verifiziert 14+ (getestet gegen 16)
Oracle Betrieb verifiziert 19c+ (getestet gegen XE 21c)
Microsoft SQL Server Betrieb verifiziert 2019+ (getestet gegen 2022)

Je Installation gibt es eine Haupt-Datenbank; ihr Typ ergibt sich aus der Verbindungs-URL (siehe unten).

Stand außerhalb von MySQL

MySQL ist am längsten im Einsatz und am besten erprobt. Auf den anderen Datenbanken sind Start, Anlage der Tabellen und die Grundfunktionen geprüft.

Für Oracle liegt eine vollständige Messung vor (28.09.2026, gegen XE 21c, frisch angelegtes leeres Schema): Alle 55 mitgelieferten Beispiele werden installiert, kein Seeder bricht ab, der Start meldet weder Fehler noch Oracle-Meldungen. Anschließend wurde für jedes der 48 Formulare jeder Schritt einzeln geprüft — öffnen, speichern, lesen, Listenansicht, Drucken — und dasselbe parallel gegen MySQL: kein einziger Schritt scheitert allein auf Oracle. Die wenigen Ausnahmen treten auf MySQL genauso auf und haben nichts mit der Datenbank zu tun.

Die Auswahllisten der Beispiele sind portabel: Statt vendor-spezifischem SQL benutzen sie displayColumns, und KCForms baut den Verkettungs-Ausdruck passend zur laufenden Datenbank. Wer in eigenen Formularen freies SQL für eine Auswahlliste schreibt, bindet sich dagegen an den Vendor, für den er es geschrieben hat.

Für PostgreSQL liegt dieselbe Messung vor (28.09.2026, gegen PostgreSQL 16, frisch angelegte leere Datenbank) — mit demselben Ergebnis: alle Beispiele installiert, keine Fehler beim Start, kein einziger Schritt scheitert allein auf PostgreSQL. Ein Datensatz mit allen Feldtypen (Umlaute, Mehrfachauswahl, Detail-Tabelle mit Berechnung) kam zeichengleich zurück wie auf MySQL, der Ausdruck ebenso.

Für SQL Server liegt dieselbe Messung ebenfalls vor (28.09.2026, gegen SQL Server 2022, frisch angelegte leere Datenbank) — mit demselben Ergebnis: alle Beispiele installiert, keine Fehler beim Start, kein einziger Schritt scheitert allein auf SQL Server, Datensatz und Ausdruck zeichengleich zu MySQL.

Eine Einschränkung bleibt dort bestehen: Die Tabelle form_script_lib hat einen zusammengesetzten Schlüssel aus Formular-ID und Dateipfad. Als NVARCHAR sind das 1128 Byte und damit mehr, als SQL Server für einen Index-Schlüssel zulässt (900). Beim Anlegen warnt der Server; fehlschlagen würde erst das Speichern einer Skript-Bibliothek mit sehr langem Pfad — rechnerisch ab etwa 386 Zeichen. Übliche Pfade bleiben deutlich darunter.

Externe Datenquellen sind von alledem nicht betroffen.

Welcher Spaltentyp je Vendor aus einem Feld entsteht — und welche Grenzen daran haengen (Zeilengroesse, Zeichen- statt Byte-Laengen, Datumsbereiche) — steht in Datenmodell: Welcher Spaltentyp entsteht?.

Wie lang ein Tabellenname werden darf

KCForms leitet Tabellennamen aus der Formular-ID und den Feldnamen ab (form_<id>_<detailtabelle>). Jede Datenbank hat dafür eine eigene Obergrenze: MySQL 64, PostgreSQL 63, Oracle und SQL Server je 128 Zeichen. KCForms kürzt entsprechend — und zwar hinten, genau so, wie PostgreSQL es von sich aus täte. Dadurch findet eine bestehende Installation ihre Tabellen unverändert wieder.

Zwei Dinge sind dabei gut zu wissen:

  • Die beiden Vendors verhalten sich unterschiedlich: MySQL weist einen zu langen Namen ab, PostgreSQL kürzt ihn still und meldet das nur als Hinweis. Vor dem Stand vom 03.10.2026 führte das auf PostgreSQL dazu, dass ein Formular mit tief verschachtelten Detail-Tabellen bei jedem Start als „broken" übersprungen wurde.
  • Wer kurze Formular-IDs vergibt, hat mehr Luft für Detail-Tabellen. Ab etwa 50 Zeichen Gesamtlänge beginnt KCForms, den Namen durch einen Kurz-Hash zu ersetzen — eindeutig, aber nicht mehr sprechend.

Die Grenze wird beim Start beim Treiber erfragt, nicht angenommen — das steht als Zeile im Protokoll (SqlDialect: erkannt … Bezeichner bis N Zeichen). Das ist vor allem bei Oracle wichtig: Erst ab Version 12.2 sind es 128 Zeichen, davor nur 30. Mit 30 läuft KCForms zwar weiter, aber fast jeder Tabellenname besteht dann nur noch aus einem Kurz-Hash; der Start weist eigens darauf hin.

Oracle: eigenes Schema statt SYSTEM

KCForms muss in ein eigenes, leeres Schema booten (nicht in SYSTEM). Einmalig als privilegierter Nutzer anlegen, dann als dieser Nutzer verbinden:

CREATE USER kcforms IDENTIFIED BY <passwort>;
GRANT CONNECT, RESOURCE TO kcforms;
GRANT UNLIMITED TABLESPACE TO kcforms;
Hintergrund: In einem nicht leeren Schema (wie SYSTEM) überspringt die Schema-Anlage ihren ersten Schritt — die Kern-Tabellen entstünden nicht.

Datenbank einstellen

Die Haupt-Datenbank wird ausschließlich über drei Umgebungsvariablen eingestellt; KCForms erkennt den Typ an der Verbindungs-URL und richtet alles Weitere (Treiber, Schema-Anlage, Ablage der Sitzungen) selbst ein.

PostgreSQL:

SPRING_DATASOURCE_URL=jdbc:postgresql://<host>:5432/kcforms
SPRING_DATASOURCE_USERNAME=kcforms
SPRING_DATASOURCE_PASSWORD=<passwort>

Zum Vergleich der MySQL-Standard:

SPRING_DATASOURCE_URL=jdbc:mysql://<host>:3306/kcforms
SPRING_DATASOURCE_USERNAME=kcforms
SPRING_DATASOURCE_PASSWORD=<passwort>

Und Oracle (in ein eigenes Schema, siehe Hinweis oben):

SPRING_DATASOURCE_URL=jdbc:oracle:thin:@<host>:1521/<service>
SPRING_DATASOURCE_USERNAME=kcforms
SPRING_DATASOURCE_PASSWORD=<passwort>

Und SQL Server (in eine eigene, leere Datenbank):

SPRING_DATASOURCE_URL=jdbc:sqlserver://<host>:1433;databaseName=kcforms;encrypt=false;trustServerCertificate=true
SPRING_DATASOURCE_USERNAME=<login>
SPRING_DATASOURCE_PASSWORD=<passwort>

Es ist kein manuelles Setzen des JDBC-Treibers, der Migrations-Pfade oder des Session-Schemas nötig — das leitet KCForms aus der URL ab.

Der Treiber für MySQL

KCForms spricht MySQL über den mitgelieferten MariaDB-Treiber. Den Treiber von Oracle (MySQL Connector/J) liefern wir aus Lizenzgründen nicht mit: Er steht unter der GPL, und deren Ausnahme gilt nur für Open-Source-Software. Für Sie ändert sich dadurch nichts. Eine vorhandene Adresse mit jdbc:mysql: gilt weiter, und Sie müssen nichts umstellen.

Beim Start steht im Protokoll, welcher Treiber spricht:

Datenbank-Treiber: MariaDB Connector/J 3.5.10 → MySQL 8.4.8

Wer lieber mit dem Treiber von Oracle arbeitet, kann ihn sich selbst besorgen und neben KCForms legen. Im Tomcat-Betrieb gehört die Datei mysql-connector-j-<version>.jar nach $CATALINA_BASE/lib/. KCForms nimmt ihn dann von selbst, und im Protokoll steht MySQL Connector/J. Wo es die Datei gibt und was beim Ablegen zu beachten ist, steht unter Voraussetzungen → Datenbank-Treiber.

Verschlüsselung ohne SSL-Angabe

Steht in der Adresse keine SSL-Angabe, verlangt KCForms eine verschlüsselte Verbindung (TLS). Der Treiber von Oracle hat in diesem Fall verschlüsselt, wenn der Server es konnte, und sonst unverschlüsselt verbunden. Ein „wenn möglich" kennt der MariaDB-Treiber nicht. Wir haben uns deshalb für „immer verschlüsselt" entschieden statt für ein stilles „unverschlüsselt".

Kann Ihr Datenbank-Server kein TLS, startet KCForms nicht. Das betrifft zum Beispiel einen MariaDB-Server in der Grundeinstellung. Hängen Sie dann useSSL=false an die Adresse an, oder richten Sie TLS am Server ein. Die Adressen, die der Installationsassistent und die Docker-Vorlage erzeugen, enthalten useSSL=false bereits.

Hinter den Kulissen: wie die Adresse übersetzt wird

Die Optionen einer jdbc:mysql:-Adresse sind in der Schreibweise von Connector/J gedacht. Ohne Connector/J im Klassenpfad übersetzt KCForms sie beim Start für den MariaDB-Treiber. Die Datei bootstrap.properties bleibt dabei unverändert.

In der Adresse wird für MariaDB zu
— (Präfix jdbc:mysql:) zusätzlich permitMysqlScheme=true
serverTimezone=X connectionTimeZone=X&preserveInstants=true
keine SSL-Angabe, sslMode=PREFERRED sslMode=trust (TLS, Zertifikat ungeprüft)
useSSL=true / requireSSL=true sslMode=trust
useSSL=true&verifyServerCertificate=true sslMode=verify-ca
useSSL=false / sslMode=DISABLED sslMode=disable
sslMode=VERIFY_IDENTITY sslMode=verify-full

Alles Weitere, etwa rewriteBatchedStatements oder allowPublicKeyRetrieval, versteht der MariaDB-Treiber selbst. Die Zeitzonen-Übersetzung ist dabei entscheidend. Ohne sie läge ein vorhandener Zeitstempel um den Abstand zwischen Server- und Datenbank-Zeitzone verschoben. Gemessen wurde das an einem Server in Europe/Berlin gegen eine Datenbank in UTC.

Neuinstallation (Greenfield)

PostgreSQL, Oracle und SQL Server sind für frische Installationen gedacht: KCForms legt seine Tabellen beim ersten Start selbst an. Eine Übernahme bestehender MySQL-Daten ist nicht eingebaut — dafür wäre ein eigener Export/Import nötig. Formulare lassen sich per Transport übertragen.

Betrieb & Verifikation

Ein Start gegen PostgreSQL protokolliert u. a.:

SqlDialect: erkannt 'PostgreSQL' → postgresql
SchemaMigrations: Vendor 'postgresql' — MySQL-Netz übersprungen (Schema via Flyway).
Started KcFormsApplication in <n> seconds

Erscheint stattdessen erkannt 'MySQL' → mysql, läuft die Instanz gegen MySQL — dann die SPRING_DATASOURCE_URL prüfen.

Start nach einem Neustart des Servers

Startet der ganze Server neu, kommen Datenbank und Anwendung gleichzeitig hoch — und die Anwendung ist meist schneller. Sie braucht die Datenbank aber sofort: noch vor der ersten Seite gleicht sie das Schema ab.

KCForms wartet deshalb beim Start auf die Datenbank, standardmäßig bis zu fünf Minuten. Erst danach gibt es auf.

Woran man das Warten erkennt

Im Protokoll steht

HikariPool-1 - Starting...

und dann minutenlang nichts. Das ist kein Hänger, sondern genau dieses Warten. Kommt die Datenbank dazu, geht es weiter:

HikariPool-1 - Added connection
Started KcFormsApplication in 133.029 seconds

Die 133 Sekunden aus diesem gemessenen Beispiel sind fast ausschließlich Wartezeit — die Anwendung selbst startet in rund fünf.

Die Wartezeit lässt sich über KCFORMS_DB_WAIT_MS (Millisekunden) anpassen. 0 schaltet sie ab, die Anwendung gibt dann beim ersten erfolglosen Versuch auf. Das ist beim Entwickeln bequem — eine falsch eingetragene Adresse meldet sich sofort statt nach fünf Minuten — im Betrieb aber nicht zu empfehlen.

Warum die Abhängigkeit in Docker-Compose nicht genügt

In der Compose-Datei steht beim Anwendungs-Container sinnvollerweise:

    depends_on:
      db:
        condition: service_healthy

Das greift jedoch nur, wenn Compose die Container hochfährt. Nach einem Neustart des Servers startet der Docker-Dienst sie über ihre Restart-Regel (restart: unless-stopped) — und dabei zählt die Abhängigkeit nicht. Die Reihenfolge ist dann Zufall. Genau deswegen muss die Anwendung selbst warten können.

Warum ein Fehlstart früher unbemerkt blieb

Läuft KCForms als WAR in einem Tomcat, hat ein Fehlstart eine unangenehme Eigenschaft: Tomcat läuft weiter, nur die Anwendung darin ist tot. Für Docker sieht der Container damit vollkommen gesund aus — docker ps meldet Up 2 hours, während jeder Aufruf mit 404 beantwortet wird. Die Restart-Regel greift nicht, denn die reagiert allein darauf, dass ein Container endet.

Ein Healthcheck macht diesen Zustand sichtbar. /api/auth/info antwortet nur, wenn die Anwendung wirklich steht:

    healthcheck:
      test: ["CMD", "curl", "-fsS", "-o", "/dev/null",
             "http://localhost:8080/api/auth/info"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 420s

start_period deckt das Warten auf die Datenbank mit ab, sonst gilt der Container währenddessen als krank. docker ps zeigt dann der Reihe nach health: starting, healthy — und wenn die Datenbank ausbleibt, unhealthy.

Ein Healthcheck startet nichts neu

unhealthy ist in einfachem Docker nur eine Anzeige. Die Restart-Regel reagiert darauf nicht; das tut nur Docker Swarm. Wer echtes Selbstheilen will, braucht einen zusätzlichen Wächter-Container — der dafür Zugriff auf den Docker-Socket braucht, und das entspricht Root-Rechten auf dem Wirt. Diese Abwägung sollte man bewusst treffen. Dass der Fall gar nicht erst eintritt, besorgt das Warten oben.