Loading...

Open Session in View (OSIV) in Spring - Aktivieren oder Deaktivieren?

Spring
30. August 2023
4 Minuten Lesezeit
Beitrag teilen:
Gefällt dir der Beitrag?
Du wirst den Newsletter lieben!

Wenn du mit Spring Boot und Hibernate arbeitest, bist du mit Sicherheit schon einmal über den Begriff “Open Session in View” (OSIV) oder die dazugehörige Property open-in-view gestolpert. Aber was genau macht diese Option und wie beeinflusst sie die Interaktion mit deiner Datenbank? Und sollte ich sie aktivieren oder deaktivieren? In diesem Artikel tauchen wir tief in das Thema ein und beleuchten die Funktionsweise und die Unterschiede zu anderen Ansätzen.

Was ist OSIV?

Open Session in View ist ein Pattern, das in Spring Boot standardmäßig aktiviert ist und über eine spezielle Option deaktiviert werden kann. Du hast bestimmt schon mal diese Warnung gesehen:

2023-08-29T17:31:48.014+02:00  WARN 65701 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning

OSIV sorgt dafür, dass die Hibernate Session für die gesamte Dauer eines HTTP-Requests geöffnet bleibt. Das klingt erstmal unspektakulär, hat aber weitreichende Auswirkungen auf die Art und Weise, wie du mit Lazy Associations und Entities in deinem Code umgehst.

// Ein typisches Lazy-Loaded-Attribut in einer Entity
@Entity
public class User {
    @Id
    private UUID id = UUID.randomUUID();
    
    @OneToMany(fetch = FetchType.LAZY)
    private List<Order> orders;
}

Ohne OSIV würdest du beim Zugriff auf user.getOrders() außerhalb einer Transaktion eine LazyInitializationException erhalten. Mit OSIV bleibt die Session offen, und du kannst auf die Bestellungen zugreifen. Sie werden, wie konfiguriert, lazy geladen.

OSIV ist ein Servlet Filter

In der Klasse OpenSessionInViewFilter implementiert Spring OSIV. Diese Klasse ist eine Implementierung des OncePerRequestFilter, welcher – wie der Name schon andeutet – genau einmal pro Request ausgeführt wird. Darin wird die Hibernate Session für die Dauer des Requests geöffnet und danach geschlossen.

// Pseudocode für den OSIV-Filter
public class OpenSessionInViewFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
        Session session = sessionFactory.openSession();
        try {
            // Hier wird der Request verarbeitet
            chain.doFilter(req, res);
        } finally {
            session.close();
        }
    }
}

OSIV und Transaktionen

Wie du am Pseudocode oben vielleicht bemerkt hast, wird keine Transaktion mit OSIV geöffnet. Wir haben lediglich eine Hibernate Session. Doch was bedeutet das eigentlich?

Die Hibernate Session ist ein leichtgewichtiger Container, der die Verbindung zur Datenbank und den Lebenszyklus von persistenten Objekten verwaltet. Es werden CRUD-Operationen (Create, Read, Update, Delete) über eine Session abgewickelt.

Ohne eine Transaktion ist es möglich, mit inkonsistenten Daten zu arbeiten. Sollte während der Verarbeitung eine andere Session die gleichen Entitäten anpassen, so kann dies nicht festgestellt werden. Dadurch kannst du schwer nachvollziehbare Bugs und Zustände in deiner Applikation erzeugen.

Sollte ich OSIV deaktivieren?

Sobald du gelernt hast wie Transaktionen in Spring funktionieren, welche states entities haben können und welche Konsequenzen daraus resultieren : ja.

OSIV macht es Anfängern erstmal einfach, mit Spring zu starten. Sie müssen sich nicht mit den Details von JPA und Hibernate auseinandersetzen. Sie erleben nicht andauernd LazyInitializationException und verzweifeln daran. Durch diese Vereinfachung ist es aber wahrscheinlicher, dass Entities in der Applikation über Transaktionsgrenzen hinweg gereicht werden. Was dann noch auf der Entwicklermaschine funktioniert, scheitert unter Last.

OSIV deaktivieren und @Transactional nutzen

Um OSIV zu deaktivieren, füge die folgende Zeile in deine application.properties ein:

spring.jpa.open-in-view=false

Da du nun nicht mehr in der Lage bist, Relationen lazy zu fetchen, solltest du im einfachsten Fall ein @Transactional um deine Controller-Methoden legen. Damit stellst du sicher, dass jeder Request atomar ist und entweder vollständig oder gar nicht angewandt wird. Und da wir damit implizit auch eine Hibernate Session öffnen, können wir unsere Relationen lazy fetchen.

Aber was ist mit der Performance? (panic!)

Keine Sorge. In 99 % aller Fälle wird diese Strategie “good enough” sein. In allen anderen Fällen benötigst du individuelle Lösungen. Vielleicht sollte der Request asynchron ausgeführt werden? Oder vielleicht kannst du ihn auf mehrere Transaktionen aufteilen. Habe immer einen Blick auf deine Performance und reagiere, sobald du entsprechende Symptome siehst.

Zum Abschluss empfehle ich dir noch, diese GitHub-Diskussion aus dem Spring-Projekt zu lesen: Log a warning on startup when spring.jpa.open-in-view is enabled but user has not explicitly opted in . Es gibt viele gute Argumente für und gegen OSIV. Setze dich damit auseinander und triff deine Wahl für dein Projekt und deinen Kontext.

Kennst du schon Marcus' Backend Newsletter?

Neue Ideen. 2x pro Woche!
Top