Wie Hibernate meine Karriere fast ruiniert hätte
Veröffentlicht: 2022-03-11Stellen Sie sich vor, Sie sind ein Java-Entwickler und stehen kurz davor, Ihr nächstes großes Projekt zu starten. Sie müssen die grundlegenden Entscheidungen treffen, die Sie für den Rest des Projekts begleiten werden. Sie möchten die beste objektorientierte Abstraktion Ihres flexiblen Datenmodells auswählen, weil Sie sich nicht mit einfachem SQL befassen möchten. Sie möchten alle Arten von Daten und idealerweise alle Arten von Datenbanken unterstützen.
Die offensichtliche Antwort ist, einfach Hibernate zu verwenden, richtig? 90 % der Java-Entwickler würden Ihnen zustimmen, aber ist das die richtige Entscheidung?
Werfen wir einen Blick darauf, was schief gehen kann, wenn Sie Hibernate blind verwenden, nur weil es der akzeptierte Standard ist.
Denken Sie an Monica, eine Java-Entwicklerin. Monica wurde vor Kurzem zur Architektin befördert und ist nun für das Layout des Technologie-Stacks für ein neues Produkt in ihrem Unternehmen verantwortlich. Sie weiß, dass es in der Java-Welt nur ein gutes Werkzeug für die Handhabung der Datenbankkommunikation gibt: Hibernate . Hibernate ist ein bekannter und unterstützter JPA-Standard. Es ist jedoch immer eine gute Idee, ein paar Dinge zu überprüfen, bevor Sie mit einem Projekt beginnen. Zum Glück kennt ihr Kollege Ben den Richtigen.
Hibernate klingt wie eine Wunderwaffe
Ben - Hallo Monica, ich möchte John vorstellen. Er ist ein Hibernate -Experte und wird Ihnen helfen.
Monica - Hey John, ich bin froh, dass du etwas Zeit für mich gefunden hast. Wir bauen also unser nächstes großes Ding, wissen Sie. Wir planen, das nächste Facebook oder Google zu werden. Arbeitsreiche Tage. Es wird riesig. Absolut fantastisch! Alle sind so aufgeregt! Ich wurde in die Rolle eines Architekten befördert, also muss ich jetzt den Stack auswählen, den wir verwenden werden. Das einzige, was fehlt, ist Beharrlichkeit …
John - Winterschlaf !
Monika – Ja! Exakt! Genau das, was ich dachte! Es scheint wie eine perfekte Übereinstimmung und das einzig Wahre für uns. Eine echte Unternehmenslösung für ein echtes Unternehmensproblem, markterprobt und mit einer langen Geschichte. Ich habe so viele positive Erfahrungen damit gehört. Allerdings habe ich ein Problem mit einem unserer Teamkollegen; er ist total dagegen. Er weiß viel über Datenbanken und hat Angst davor, eine weitere Ebene zwischen unserer Anwendung und der Datenbank hinzuzufügen. Er ist superschlau, und ich brauche ein paar wirklich gute Argumente, um ihn davon zu überzeugen, dass dies eine gute Entscheidung ist. Kannst du mir damit helfen?
Johannes – Natürlich! Ich werde glücklich sein zu. Hibernate ist in der Tat ein hervorragendes Tool. Es wird häufig in großen, echten Unternehmenslösungen wie Banken eingesetzt. Sie können damit nichts falsch machen. Denken Sie an Persistenz: Wählen Sie Hibernate . Wenn Sie in Java schreiben, ist dies absolut die richtige Wahl, außerdem haben Sie Portierungen für andere Sprachen. Sehen Sie, wie viele Stellenbeschreibungen es erfordern!
Monika – da stimme ich absolut zu! Ich habe die gleichen Gefühle darüber. In einem früheren Projekt haben wir hauptsächlich SQL über das einfache alte JDBC verwendet. Lächerlich! Ich kenne! Aber hier ist die Sache: Wir haben wirklich schlaue SQL-Leute im Team und als sie sahen, dass SQL von Hibernate generiert wurde, wurden sie nervös. Es schien hässlich und unlesbar; wird das in Zukunft ein Problem sein?
John - Schau. DBA-Jungs haben eine andere Perspektive. Sie haben Angst vor Hibernate , weil es ihre Rolle im Projekt zu ersetzen scheint. Darüber hinaus verfügen Datenbanken über integrierte Abfrageoptimierer, sodass Sie sich keine Gedanken darüber machen müssen, wie diese Abfragen tatsächlich aussehen. Die Datenbank optimiert es für Sie. Es dreht sich alles um schnelle Entwicklung, was SQL nicht leisten kann.
Monika - Wirklich?! Kein Umgang mehr mit SQL? Tolle! Letztes Mal hat ein DBA wochenlang versucht, einige Abfragen zu optimieren. Wochen! Oh, es ist mir so peinlich, Ihnen das zu sagen, aber wussten Sie, dass wir … gespeicherte Prozeduren verwenden (lacht). Oh, es war so ein Durcheinander. Können Sie glauben, dass das Projekt es immer noch verwendet? Die Leute da draußen tun mir so leid. Sie müssen diesen mühsamen Code immer wieder schreiben. Ich frage mich, ob es immer noch ein Java- oder SQL-Projekt ist?
John - Das ist genau der Unterschied zwischen einem objektorientierten Ansatz und einem relationalen. Es handelt sich um eine sogenannte objektorientierte Impedanzfehlanpassung. Hibernate kann diese Lücke schließen. Entwickler können sich auf den Aufbau der Geschäftslogik konzentrieren. Push-Features machen Stakeholder und das gesamte Management glücklich. Erledige die Dinge, die am wichtigsten sind: Business! Viel Boilerplate-Code wird verschwinden, und Sie haben eine magische, unsichtbare, aber zuverlässige Verbindung zwischen der Logik und den Daten.
Monica - Gegenseitige Zusammenarbeit. Volle Synergie. Als wäre die Datenbank von Anfang an Teil der Sprache gewesen. Ich bin so glücklich, dass ich ein Anführer dieses technologischen Vertrauensvorschusses sein darf. Es ist wie die Warp-Geschwindigkeit im Software-Trek.
Johannes - Ja! Du hast es!
Monica - Oh Gott, ich bin so aufgeregt! Danke, Johannes! Ich bin bereit!
Wachstumsschmerzen mit unflexiblen Lösungen
Monica – Hey John, erinnerst du dich an das Projekt, über das wir letztes Jahr gesprochen haben?
John - Sicher. Wie geht's?
Monica - Wir werden bald mit der Produktion beginnen. Alles ist in Ordnung, aber einige Fragen sind aufgetaucht.
John - Sicher, schlag mich.
Monica - Nun, wir können unser Datenbankschema nicht mehr von Grund auf neu erstellen. Was ist der beste Weg, um Schemaänderungen ohne Datenverlust zu unterstützen?
John - Zunächst einmal ist Hibernate nicht als Produktionsmigrationstool gedacht. Verwenden Sie etwas wie FlywayDB oder Liquibase. Es ist ziemlich einfach. Sie schreiben Migrationsskripts auf und aktualisieren dann das Entitätsmodell zusammen mit den Hibernate -Zuordnungen, damit es mit der tatsächlichen Datenbankstruktur synchron bleibt.
Monica - Hm, ich verstehe. Wir haben im vorherigen Projekt nur eine einfache SQL-Migration verwendet.
John - Das ist auch in Ordnung. Solange Sie das Entitätsmodell und das Schema synchron halten, machen Sie es wie Sie wollen.
Monika - Ich verstehe. Es gibt noch etwas. Wir kämpfen immer mit faulen/eifrigen Abrufproblemen. Irgendwann haben wir uns entschieden, alles eifrig zu machen, aber es scheint suboptimal zu sein, und außerdem ist es manchmal nicht möglich, auf einige Felder zuzugreifen, weil es keine Sitzung gibt, oder so etwas. Ist das normal?
John – Sie müssen mehr über Hibernate erfahren. Die Zuordnung aus der Datenbank ist nicht einfach. Grundsätzlich gibt es mehrere Möglichkeiten, dies zu tun. Sie müssen nur einen Weg wählen, der für Sie funktioniert. Lazy Fetching gibt Ihnen die Möglichkeit, diese Objekte bei Bedarf zu laden, aber Sie müssen innerhalb einer aktiven Sitzung arbeiten.
Monica – Wir kämpfen immer noch damit, welche Datenbank-Engine wir für die endgültige Bereitstellung verwenden sollen. Ich dachte, Hibernate sei portabel, aber wir haben einige native Abfragen, die etwas MS SQL-Magie verwenden, und wir würden eigentlich gerne mit MySQL in der Produktion arbeiten.
John - Hibernate gibt Ihnen Flexibilität, solange Sie getrennte Kriterien oder HQL verwenden; Alle nativen Abfragen binden Ihre Lösung einfach an die Datenbank.
Monica - Scheint, als müssten wir uns dann an MS SQL halten. Letzte Frage: Mein Teamkollege sagte, dass es in HQL kein „Limit“-Schlüsselwort gibt. Ich dachte, er macht Witze, aber ich konnte es auch nicht finden. Sorry für die blöde Frage…
John – In der Tat gibt es in HQL kein „Limit“-Schlüsselwort. Sie können dies über das Abfrageobjekt steuern, da es datenbankherstellerspezifisch ist.
Monica - Scheint seltsam, dass alle anderen Elemente in HQL sind. Egal. Vielen Dank für Ihre Zeit!
Wir hacken jetzt wieder Lösungen in SQL zusammen
Monica - John, am Anfang wollten wir uns nicht mit SQL befassen, aber jetzt scheint es so, als müssten wir es tun. Unsere Bedürfnisse wachsen, und es scheint, als führt kein Weg daran vorbei. Es fühlt sich falsch an, aber wir haben begonnen, SQL wieder täglich zu verwenden.

John - Nun, es ist nicht falsch. Sie mussten sich von Anfang an nicht auf die Datenbank konzentrieren. Wenn das Projekt jedoch wächst, ist es gut, SQL zu verwenden und an der Leistungsoptimierung zu arbeiten.
Monica - Manchmal verbringen wir Tage damit, nach Fehlern zu suchen. Es scheint, als müssten wir von Hibernate generiertes SQL analysieren, weil wir keine Ahnung haben, warum es nicht wie erwartet funktioniert und unerwartete Ergebnisse liefert. Wir sind auf einige Probleme gestoßen, die im Hibernate -Bugtracker bekannt sind. Darüber hinaus ist es schwierig, ordnungsgemäße Migrationen zu schreiben und gleichzeitig das Entitätsmodell synchron zu halten. Es ist zeitaufwändig, da wir viel über die Interna von Hibernate lernen und vorhersagen müssen, wie es funktionieren wird.
John - Es gibt immer eine Lernkurve. Sie müssen nicht viel schreiben, aber Sie müssen wissen, wie es funktioniert.
Monica - Die Arbeit mit größeren Datensätzen ist auch nervig. Kürzlich haben wir einen massiven Import in die Datenbank durchgeführt, und es war schmerzhaft langsam. Dann fanden wir heraus, dass wir die Sitzung löschen mussten, um sie schneller zu machen. Trotzdem ist es immer noch deutlich langsamer, also haben wir uns entschieden, es als einfache SQL-Anweisungen umzuschreiben. Komischerweise war das Schreiben von einfachem SQL tatsächlich der schnellste Weg, also haben wir uns entschieden, dies als letzte Option zu tun.
John - Import ist kein objektorientierter Prozess. Hibernate konzentriert sich auf objektorientiertes Design. Denken Sie daran, dass Sie immer native Abfragen verwenden können.
Monica - Können Sie mir helfen zu verstehen, wie der Hibernate- Cache funktioniert? Ich verstehe es einfach nicht. Es gibt einige Caches der ersten/zweiten Ebene. Worum geht es?
John - Sicher. Es ist ein sogenannter Cache auf Transaktionsebene mit persistenten Daten. Es ist möglich, einen Cache auf Cluster- oder JVM-Ebene Klasse für Klasse und Sammlung für Sammlung zu konfigurieren. Sie können sogar einen geclusterten Cache anschließen. Denken Sie jedoch daran, dass Caches keine Änderungen bemerken, die von einer anderen Anwendung am persistenten Speicher vorgenommen wurden. Sie können jedoch so konfiguriert werden, dass abgelaufene zwischengespeicherte Daten regelmäßig gelöscht werden.
Monica - Tut mir leid, ich glaube, ich habe einen schlechten Tag. Kannst du das etwas näher erläutern?
John - Sicher. Immer wenn Sie ein Objekt an save
, update
, saveOrUpdate
oder es über load
, get
, list
, iterate
oder scroll
abrufen, wird dieses Objekt dem internen Cache der Sitzung hinzugefügt. Sie können das Objekt und seine Sammlungen auch aus dem First-Level-Cache entfernen.
Monika - Äh…
John - Zusätzlich können Sie Cache-Modi steuern. Sie können den normal
Modus verwenden, um Elemente im Second-Level-Cache zu lesen und zu schreiben. Verwenden Sie get
-Modus, um von der zweiten Ebene zu lesen, aber Sie können nicht zurückschreiben. Verwenden Sie put
, was dasselbe ist wie get
aber Sie können nicht von der zweiten Ebene lesen. Sie können auch den refresh
verwenden, der auf die zweite Ebene schreibt, aber nicht daraus liest, und die Eigenschaft use minimal puts
umgehen, wodurch eine Aktualisierung des Caches der zweiten Ebene für alle aus der Datenbank gelesenen Elemente erzwungen wird.
Monika - Ich verstehe. OK. Lassen Sie mich darüber nachdenken. Oh, es ist spät, ich muss gehen. Vielen Dank für Ihre Zeit!
John - Gern geschehen!
Den Winterschlaf aufgeben
Monica - John, ich dachte, wir würden in eine neue Ära der Softwareentwicklung eintreten. Ich dachte, wir machen einen Lichtjahrsprung. Aber nach vier Jahren scheint es, als hätten wir es immer noch mit denselben Problemen zu tun, nur aus einem anderen Blickwinkel. Ich musste Hibernate -Architektur, Konfiguration, Protokollierung, Benennungsstrategien, Tuplizer, Entity-Name-Resolver, erweiterte Identifier-Generatoren, Identifier-Generator-Optimierung, Union-Subclasses, XDoclet-Markup, bidirektionale Assoziationen mit indizierten Sammlungen, ternäre Assoziationen, idbag und das Mischen von implizitem Polymorphismus lernen andere Vererbungszuordnungen, das Replizieren von Objekten zwischen zwei verschiedenen Datenspeichern, getrennte Objekte und automatische Versionierung, Verbindungsfreigabemodi, zustandslose Sitzungsschnittstelle, Taxonomie der Sammlungspersistenz, Cache-Ebenen, verzögertes oder eifriges Abrufen und vieles mehr. Trotz allem, was ich weiß, scheint es, als hätten wir schwer versagt. Es ist ein Software-Fiasko! Ultimatives Scheitern! Katastrophe! Armageddon!
John - Warte! Was ist passiert?
Monica - Wir haben eine Sackgasse erreicht. Unsere Anwendungsleistung ist lächerlich langsam! Um einen Bericht zu bekommen, müssen wir zwei Tage warten! Zwei Tage, um tatsächlich ein Dashboard für einen Kunden zu erstellen. Das bedeutet, dass wir jeden Tag unseren Berechnungsschwanz erhöhen müssen, während unser Dashboard immer veralteter wird. Unser DBA-Experte hat zwei Monate daran gearbeitet, einige Abfragen zu optimieren, während unsere Datenbankstruktur ein komplettes Durcheinander ist. Es gibt Entwickler, die ihn unterstützen, aber das Problem ist, dass der DBA in SQL denkt, und die Entwickler verbringen Tage damit, dies in getrennte Kriterien oder das HQL-Format zu übersetzen. Wir versuchen, so viel wie möglich natives SQL zu verwenden, da die Leistung im Moment entscheidend ist. Wie auch immer, wir können nicht viel tun, da das Datenbankschema einfach falsch zu sein scheint. Aus der objektorientierten Perspektive fühlte es sich richtig an, aber aus der relationalen Perspektive wirkt es lächerlich. Ich frage mich: Wie ist das passiert? Die Entwickler sagen uns, dass das Ändern der Entity-Struktur ein enormer Aufwand sein wird, also können wir uns das nicht leisten. Ich erinnere mich, dass es beim vorherigen Projekt ein Durcheinander war, aber wir sind nie an einem so kritischen Punkt gelandet. Wir konnten eine ganz andere Anwendung schreiben, um mit den Daten zu arbeiten. Jetzt ist es riskant, diese generierten Tabellen zu ändern, da es wirklich schwierig ist, sicherzustellen, dass sich das Entitätsmodell immer richtig verhält. Und das ist noch nicht einmal das Schlimmste! Um die Leistung zu steigern, müssen wir nicht nur Datenbankprobleme lösen, sondern auch Probleme mit der gesamten Schicht zwischen unserer Datenbank und der Anwendung. Es ist überwältigend! Wir haben diese neuen Typen, wissen Sie, Berater. Sie versuchen, Daten zu extrahieren, sie in einen anderen Speicher zu legen und dann Berechnungen von außen durchzuführen. Es dauert alles zu lange!
John - Ich weiß nicht, was ich sagen soll.
Monica - Du siehst John; Ich will dir keine Vorwürfe machen. Ich habe mich für Hibernate entschieden, um all diese Probleme zu lösen, aber jetzt habe ich gelernt, dass es keine Wunderwaffe ist. Der Schaden ist angerichtet und irreversibel. Eigentlich möchte ich Sie etwas fragen: Ich habe die letzten vier Jahre meiner Karriere damit verbracht, mich mit Hibernate- Sachen zu beschäftigen. Es scheint, dass ich in meiner jetzigen Firma keine Zukunft habe. Können Sie mir helfen?
Also, was ist die Lektion gelernt?
John - Hey, Peter, lass mich Monica vorstellen.
Peter - Hey, Monika! Wir bauen unser neues nächstes großes Ding, wissen Sie. Es wird riesig! Wir wollen wie Uber sein! Weißt du vielleicht, wie Beharrlichkeit…
Monica - Nicht überwintern !
Einpacken
Monica ist Hibernate- Expertin. Allerdings war Hibernate in diesem Fall eine falsche Entscheidung. In dem Moment, in dem sie entdeckte, dass ihre Lösung zu einem größeren Problem wurde als das Original, war dies die größte Bedrohung für das gesamte Projekt.
Daten sind der zentrale Zweck der Anwendung und wirken sich, ob Sie wollen oder nicht, auf die gesamte Architektur aus. Wie wir aus der Geschichte gelernt haben, verwenden Sie Hibernate nicht nur, weil Ihre Java-Anwendung eine Datenbank verwendet oder wegen sozialer Beweise. Wählen Sie eine Lösung, die Flexibilität umfasst. Es gibt viele Optionen für robuste JDBC-Wrapper, wie JdbcTemplate oder Fluent JDBC Wrapper. Alternativ gibt es andere leistungsstarke Lösungen, wie z. B. jOOQ.