Hibernate-reactive: openSession() gibt Fehler zurück "Dies muss in der Vert.x-Ereignisschleife ausgeführt werden"

Erstellt am 12. Mai 2021  ·  7Kommentare  ·  Quelle: hibernate/hibernate-reactive

Hi,

Bisher war Vertx bei der Verwendung der reaktiven API von Hibernate (1.0.0.CR4) einfach vor mir verborgen. Aber ich muss eine API bereitstellen, um eine Sitzung zurückzugeben, die geöffnet bleibt, bis der Client, der diese API verwendet, entscheidet, sie zu schließen.
Ich führe einen Junit-Test durch und habe die folgende API:

    public Stage.Session openSession() throws ExecutionException, InterruptedException {
        if (session != null && session.isOpen()) {
            session.close();
        }
        Stage.Session newSession = sessionFactory.openSession();
        this.session = newSession;
        return newSession ;
   }

Und in meinem Junit-Test:
Stage.Session session = deviceRepository.openSession();
Beim Ausführen des Codes bekomme ich den Fehler:
This needs to be run on the Vert.x event loop
Ich habe versucht, den Code auf viele verschiedene Arten umzugestalten, aber es ist mir nicht gelungen, ihn zum Laufen zu bringen.

Können Sie mir bitte Ihre Empfehlung geben, wie man es richtig macht?

Vielen Dank.

Hilfreichster Kommentar

Ja, werde ich

Alle 7 Kommentare

Hi,
Das Problem mit der Sitzung besteht darin, dass sie nicht threadsicher ist. Die Verwendung in verschiedenen Threads kann zu Problemen führen, die schwer zu debuggen sind. Auch wenn eine neue Sitzung erstellt wird, ist sie an einen Vert.x-Kontext gebunden und muss danach im selben Kontext verwendet werden.

Dies wird normalerweise von Hibernate Reactive erledigt, wenn man SessionFactory#withTransaction und SessionFactory#withSession .

Ihre Tests funktionieren nicht, weil sie in einem JUnit-Thread und nicht in einem Vert.x-Thread ausgeführt werden.
Eine Möglichkeit, dieses Problem in JUnit 4 zu lösen, ist eine Regel, die in der Bibliothek io.vertx:vertx-unit:4.0.3 :

<strong i="13">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();

Dadurch wird sichergestellt, dass Ihre Tests in einem Vert.x-Kontext ausgeführt werden .

Dies reicht jedoch nicht aus, Sie müssen auch sicherstellen, dass die Sitzung an denselben Vert.x-Kontext gebunden ist, der von der Regel definiert wird.

VertxInstance-Dienst:

Im Allgemeinen können Sie dies erreichen, indem Sie einen benutzerdefinierten VertxInstance-Dienst erstellen .

Dieser Dienst teilt Hibernate Reactive mit, wie die richtige Vert.x-Instanz abgerufen wird, die beim Erstellen der Sitzung verwendet werden soll.
Wenn Sie die SessionFactory programmgesteuert erstellen, sehen Sie hier ein Beispiel dafür:

Configuration configuration = new Configuration();
StandardServiceRegistryBuilder builder = new ReactiveServiceRegistryBuilder()
                .addService( VertxInstance.class, (VertxInstance) () -> getMyVertxInstance())
                .applySettings( configuration.getProperties() );
StandardServiceRegistry registry = builder.build();
SessionFactory sessionFactory = configuration.buildSessionFactory( registry );

Alternativ können Sie es mit dem ServiceLoader-Mechanismus des JDK definieren :

  1. Fügen Sie eine Textdatei namens org.hibernate.reactive.vertx.VertxInstance unter
    /META-INF/services/
  2. Die Textdatei enthält den Pfad zu der Klasse, die die Schnittstelle VertxInstance implementiert:
    org.myproject.MyVertxProvider

Jetzt ruft Hibernate Reactive eine Instanz von MyVertxProvider wenn eine Vert.x-Instanz benötigt wird und wenn Ihr Code im gleichen Vert.x-Kontext ausgeführt wird, sollte alles funktionieren.

Behebung des Problems mit JUnit 4:

Zurück zu den Tests, eine Möglichkeit, sie zu beheben, wäre:

<strong i="41">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();

...

Configuration configuration = new Configuration();
StandardServiceRegistryBuilder builder = new ReactiveServiceRegistryBuilder()
                .addService( VertxInstance.class, (VertxInstance) () -> vertxContextRule.vertx() )
                .applySettings( configuration.getProperties() );
SessionFactory sessionFactory = configuration.buildSessionFactory(  builder.build() );

Wenn Sie die Regel nicht verwenden, können Sie Code in einem bestimmten Vert.x-Kontext wie folgt ausführen:

Context currentContext = Vertx.currentContext();
currentContext.runOnContext( event -> {
   // Here you should be able to use the session
});

Sie sollten das, was Sie gerade geschrieben haben, als FAQ zur Website oder wo auch immer hinzufügen.

Ja, werde ich

@DavideD Vielen Dank für Ihre Erklärung. Vielen Dank.

Ich habe ein Problem erstellt, um diese Änderungen an der Dokumentation/Website zu verfolgen: https://github.com/hibernate/hibernate-reactive/issues/751

Ich werde dieses Thema schließen. Fühlen Sie sich frei, weitere Fragen zu stellen, wenn etwas anderes nicht klar ist.

Dankeschön.

@DavideD Ist es möglich, den folgenden Code, den Sie zuvor erwähnt haben, mit JUnit 5 zu verwenden?

Context currentContext = Vertx.currentContext();
currentContext.runOnContext( event -> {
   // Here you should be able to use the session
});

Ja, dieser Code ist Vert.x, nicht JUnit.

Aber es ist keine äquivalente Erweiterung für JUnit 5 von:

<strong i="8">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen