Lokaler Entwicklungsserver

DaBe1812

Mitglied
Moin zusammen,

ich hätte da mal ein Problem mit meiner lokalen Entwicklung.

Wir haben in IntelliJ ein Multi-Modul-Projekt. Jakarta EE mit Vaadin Frontend.

Dazu haben wir die Module
  • Datenbank
  • Backend
  • Frontend
  • WAR
  • Deployment (Kopiert alle Sourcen in den Main-Target-Folder)
Problem war/ist wir haben lokal einen WLP installiert, zum testen. Das heißt, damit ich lokal testen kann, müssen immer die Sourcen kompiliert werden und der Server gestartet werden. DAs kostet dann für jede Änderung mindestens 5 Minuten.

Außerdem ist die Datenbank für lokal aktuell dieselbe, wie die Entwicklungsdatenbank. Jetzt kam der Fall, der kommen musste, ich hatte lokal ein paar Daten umgestellt, die Änderung an den Daten ging beim Testen an die Entwicklungs-Datenbank und damit konnten dann alle anderen nicht mehr arbeiten und der Server in der Entwicklung hat auch nur noch Fehler geworfen.

Meine Idee war zum einen einen WLP in der Anwendung einzubinden, damit man lokal testen kann über das maven goal liberty:dev. Das funktioniert nur solala,weil der liberty liegt in Frontend, d.h. ich muss die Module Datenbank und Backend immer erst kompilieren, wenn ich etwas im Frontend testen möchte. Des weiteren funktionieren dadurch scheinbar auch nur Haltepunkte im Frontend, was beim Debuggen doch eher ärgerlich ist.

Zuletzt habe ich wegen des Datenbank-Problem noch eine lokale H2 Datenbank eingebunden, welche mit den aktuellen Dev-Daten bespielt wird. Da ist aber das Problem, dass diese trotz Oracle-Modus Probleme mit einigen Spaltennamen hat, aber jetzt laufe ich zusätzlich auf ein Problem mit
TypedQuery.setMaxResults und
TypedQuery.setFirstResult,
weil H2 scheinbar mit den Begriffen nichts anfangen kann, was ich aber nicht verstehe, weil ich eigentlich dachte, dass dafür JPA solche Sachen in H2 übersetzt.

Könnt ihr mit der Beschreibung etwas anfangen und mir evtl. ein wenig helfen?
 

KonradN

Super-Moderator
Mitarbeiter
Neben den Testcontainern kommt mir auch noch die folgenden Punkte in den Sinn:

a) Unabhängig von Docker und Co: Als Entwickler sollte man immer eine Möglichkeit haben, seinen Code richtig auszuführen. Das kann zur Not auch eine Umgebung sein, die man selbst aufgebaut hat (Also z.B. direkt auf dem Entwicklungsrechner oder in einer/mehrerer VMs). Das hat aber den Nachteil, dass ein Entwicklungssystem sehr viel an Komplexität gewinnt, was zu entsprechenden Aufbauzeiten und auch zu grossen Maintenenance-Aufwänden führt. Halt etwas, das durch die Testcontainer vermieden wird und das auch mein Ratschlag wäre...

b) Gliederung der Module: Die Möglichkeit, schnell seine Umgebung zu starten, ist aus meiner Sicht existenziell. Hier sollte man immer einen Weg vorsehen, wie man seine Umgebung mit Debuggeranbindung starten kann. Hier kommt dann aus meiner Sicht vermutlich das Liberty Maven Plugin ins Spiel. (Evtl. gibt es aber auch noch andere Möglichkeiten. Zu WLP kann ich nicht ganz so viel sagen, da ich es bsiher nicht gross benutzt habe. Wir setzen auf andere Technologien / Frameworks)

c) Mit den H2 Problematiken: Habe ich das richtig verstanden, dass Du H2 nutzt, aber Du den oracle mode gesetzt lässt? Aber das meintest Du vermutlich nicht und Du hast org.hibernate.dialect.H2Dialect oder so als mode gesetzt...
Das mit den setMaxResults/setFirstResult läuft ja auf ein OFFET ... FETCH NEXT ... SQL Query hinaus. Hier ggf. mal das Query im Detail ansehen um zu schauen, was da erstellt wurde. Fehlt evtl. ein ORDER BY oder so? Sowas kann man dann im Detail weiter prüfen, wenn man sich anschaut, was denn da an SQL generiert wurde.

Aber das mit den Testcontainern macht aus meiner Sicht am meisten Sinn und das solltest Du weiter verfolgen. Und statt H2 dann evtl. ein PorstgreSQL Container (falls es da nichts brauchbares von Oracle geben sollte)....
 

DaBe1812

Mitglied
Okay, in Docker müsste ich mich mal reinarbeiten, das Thema habe ich bisher erfolgreich vermeiden können. Wie muss ich mir das grob vorstellen?
Alle meine Module sind da irgendwie als JAR oder EAR drin und der Server läuft fröhlich vor sich hin, bis ihn einer runterfährt?

Da wir im Entwicklerteam mehr als nur ich sind, war meine Idee, dass das aktuelle Setup komplett im Git liegt und damit jeder immer die komplette Umgebung hat. Bisher war es immer so, dass wenn jemand etwas im WLP geändert hatte (weil er z.B. ein zusätzliches Feature gebraucht hat) dann musste er das immer kommunizieren, damit jeder im Team das Feature bei seinem lokalen WLP auch aktiviert, sonst konnte es eben zu Fehlern kommen. So wäre jetzt alles zentral im Repository und keiner muss mehr Konfigurieren.

Für "schnelles" Testen meiner Arbeit hab ich immer Unittests geschrieben, die kann ich einfach direkt starten und gucken, ob die Methoden das machen, was sie sollen. Problem ist dabei aber auch immer gewesen, dass dann keine Datenbank verwendet werden konnte, weil die ja per JNDI eingebunden ist und dann im Test, ohne Server nicht da ist. Oder Fremdsysteme, die man per Rest abfragen will. Da musste ich dann immer alles Mocken, statt es einfach schnell "richtig" auszuführen.

Ich verwende lokal H2 und auf dem Server haben wir Oracle. Dafür kann man in H2 den Oracle Mode setzen:
XML:
<dataSource id="DB" jndiName="jdbc/appDataSource" transactional="false">
    <jdbcDriver libraryRef="H2Lib"/>
    <properties URL="jdbc:h2:mem:testdb;MODE=Oracle;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'classpath:scripts/h2-init-logger.sql'"
                password="" user="sa"/>
</dataSource>
Angeblich ist dann der Befehlssatz nicht ganz so weit weg.

Ich habe jetzt von JPQL auf CriteriaBuilder umgestellt, das funktioniert besser, aber ich laufe immer noch auf den Fehler in der Pagination:
Das ist der Code:
Java:
TypedQuery<LoggingRecord> query = em.createQuery(cq);

if (offset > 0) {
    query.setFirstResult(offset);
}

if (pageSize > 0) {
    query.setMaxResults(pageSize);
}

return query.getResultList();
Und das der Fehler:
Code:
There was an exception while trying to navigate to 'log_reader' with the root cause 'org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax Fehler in SQL Befehl "SELECT ID AS a1, LOG_DATE AS a2, LOG_LEVEL AS a3, LOG_ROW AS a4, LOGGER AS a5, MARKER AS a6, MESSAGE_TXT AS a7, THROWABLE AS a8 FROM LOGGING ORDER BY LOG_DATE DESC [*]LIMIT ? OFFSET ?"

Ich denke ja mal, dass der Stern den Fehler markieren soll, das wäre damit Limit.
 

Oneixee5

Top Contributor
Wenn ihr Docker (noch) nicht verwendet, dann sie dir https://podman.io/ an. Podman steht unter Apache Lizenz. Wenn du Docker gewerblich nutzen möchtest, dann benötigst du eine kostenpflichtige Lizenz. Bei uns, mit den vielen VM's ist das manchmal problematisch. Kubernetes kann mit Podman genauso gut umgehen.
 

KonradN

Super-Moderator
Mitarbeiter
Wie muss ich mir das grob vorstellen?
Container sind einfach leichtgewichtige virtuelle Maschinen. Leichtgewichtig, weil nicht wirklich eine komplette virtuelle Maschine bereit gestellt wird. Und der grosse Vorteil, dass neue Container sehr einfach und schnell erzeugt werden können.

war meine Idee, dass das aktuelle Setup komplett im Git liegt und damit jeder immer die komplette Umgebung hat.
Ja, genau das soll das Ziel sein. Testcontainer ist dabei einfach eine Lösung, um Testumgebungen bei Bedarf schnell zu erzeugen. Wenn ich also bei unseren Projekten einen Microservice starte (Wir nutzen Quarkus), dann werden die notwendigen Docker Container erzeugt und gestartet. (Das ist dann bei uns z.B. ein PostgreSQL Container und der Container mit dem Quarkus Service). Dabei gibt es dann auch gewisse Konifgurationsmöglichkeiten so gibt es z.B. SQL Skripte, die beim Start direkt gestartet werden um die Datenbank zu befüllen.

Die Integrationstests sind dann unter dem Strich ein Verzeichnis in der Sourceverwaltung, die dann mit Bruno geöffnet werden.

Ob man nun Testcontainer, Docker, ... nutzt ist dabei egal. Wichtig ist unter dem Strich nur, dass Du halt für Tests eine Umgebung starten kannst mit genau Deinem Entwicklungsstand. Dabei kannst Du mehr oder weniger automatisieren. Je mehr Du automatisiert hast, desto einfacher ist es für ein Team, da zu entwickeln.

Testcontainer ist ein Weg der Automatisierung. Evtl. hilft es, wenn ich einmal beschreibe, wie das bei uns aussieht (Ausgangslage ein neuer Laptop):
  • Ein Entwickler lädt sich bei uns einfach IntelliJ und Docker herunter und installiert beides.
  • in Intellij öffnet man das Project von der Sourcecode Verwaltung
  • Intellij lädt dann - nach Abfrage - automatisch direkt einige AddOns herunter
  • Der Entwickler lädt dann noch das richtige OpenJDK herunter in IntelliJ
==> Alles fertig (ok, zwei Konfigurationen für Maven und Docker fehlen doch, aber das ist erst einmal unwichtig) - nun kann in mvn install gestartet werden ==> Der Bau und alle Tests sollten direkt durchlaufen...
==> Jetzt kann direkt ein Service des Projektes gestartet werden - per Run oder Debug. Es ist nichts weiter notwendig. Es werden automatisch die notwendigen Testcontainer erzeugt und in Docker gestartet. Wenn man es stoppt, dann verschwinden die Container direkt wieder ...
Die Idee, die hier deutlich werden soll, ist der hohe Grad der Automatisierung. Es muss nichts mehr gross gemacht werden. Ein Entwicklungsrechner muss ich nicht gross vorbereitet werden. Das vereinfacht auch das Onboarding von Entwicklern.


Ich denke ja mal, dass der Stern den Fehler markieren soll, das wäre damit Limit.
Wenn man sich https://h2database.com/html/features.html anschaut, dann fällt mir auf, dass bei vielen Modis explizit geschrieben steht: "LIMIT / OFFSET clauses are supported." aber beim Oracle Mode steht das nicht.
Man findet aber dann bei SO teilweise Hinweise, dass man sowas ggf. einschalten kann, siehe z.B. https://stackoverflow.com/a/70702801

Aber ggf. solltest Du einfach einmal schauen, ob Du den Oracle Modus nicht einfach weg lässt. Wenn Ihr JPA nutzt, dann solltet Ihr euch auf einer Ebene über der Datenbank befinden und nicht direkt auf fixe Datenbank-Features setzen. Überlasst das doch der JPA Implementation. (Setzt dann voraus, dass Ihr z.B. kein SQL selbst vorgebt sondern wenn dann nur JPQL nutzt und so ... So dass ihr eben nicht auf Datenbankebene herunter geht. Dann kann man in Testumgebungen auf andere Datenbanken zugreifen wie H2 aber auch postgresql oder so)
 

thecain

Top Contributor

Ich würde mich persönlich nicht zu lange mit H2 oder auch Postgresql quälen.

Wenn die Anforderung nach mehreren dbms nicht besteht, würde ich versuchen in dev und test so nahe an Prod zu sein wie möglich. Ja, JPA sollte abstrahieren, aber wenn ich potentielle inkopabilitäten im vorneherein ausschliessen kann, mache ich das.

Docker und Testcontainers benötigt einiges an einarbeitung, ist aber eine riiiese Erleichterung die ich in meinem Setup nicht mehr missen möchte.

Wenn ich nur an die Zeiten mit x installierten JBoss versionen und dem rumkopieren von WARs und standalone.xmls zurückdenke wird mir graus
 

Oben