Hibernate-reactive: openSession () возвращает ошибку "Это необходимо запустить в цикле событий Vert.x"

Созданный на 12 мая 2021  ·  7Комментарии  ·  Источник: hibernate/hibernate-reactive

Привет,

до сих пор Vertx был просто скрыт от меня при использовании реактивного API Hibernate (1.0.0.CR4). Но мне нужно предоставить API, чтобы вернуть сеанс, который будет оставаться открытым до тех пор, пока клиент, использующий этот API, не решит закрыть его.
Я запускаю тест Junit, и у меня есть следующий 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 ;
   }

И в моем тесте junit:
Stage.Session session = deviceRepository.openSession();
Когда я запустил код, я получил ошибку:
This needs to be run on the Vert.x event loop
Я пытался реорганизовать код разными способами, но мне не удалось заставить его работать.

Не могли бы вы посоветовать, как это сделать правильно?

Спасибо.

Самый полезный комментарий

Да, я согласен

Все 7 Комментарий

Привет,
Проблема с сеансом заключается в том, что он не является потокобезопасным, его использование в разных потоках может вызвать проблемы, которые трудно отладить. Кроме того, когда создается новый сеанс, он привязан к контексту Vert.x и после этого должен использоваться в том же контексте.

Обычно этим занимается Hibernate Reactive при использовании SessionFactory#withTransaction и SessionFactory#withSession .

Ваши тесты не работают, потому что они выполняются в потоке JUnit, а не в потоке Vert.x.
Один из способов решить эту проблему в JUnit 4 - использовать правило, включенное в библиотеку io.vertx:vertx-unit:4.0.3 :

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

Это обеспечит выполнение ваших тестов в контексте Vert.x.

Однако этого недостаточно, вам также необходимо убедиться, что сеанс привязан к тому же контексту Vert.x, который определен правилом.

Сервис VertxInstance:

Обычно это достигается путем создания настраиваемой службы VertxInstance .

Эта служба сообщает Hibernate Reactive, как получить правильный экземпляр Vert.x для использования при создании сеанса.
Если вы создаете SessionFactory программно, вот пример того, как вы можете это сделать:

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 );

В качестве альтернативы вы можете определить его с помощью механизма ServiceLoader JDK :

  1. Добавьте текстовый файл с именем org.hibernate.reactive.vertx.VertxInstance под
    /META-INF/services/
  2. Текстовый файл будет содержать путь к классу, реализующему интерфейс VertxInstance :
    org.myproject.MyVertxProvider

Теперь Hibernate Reactive будет вызывать экземпляр MyVertxProvider когда ему нужен экземпляр Vert.x, и если ваш код работает в том же контексте Vert.x, все должно работать.

Устранение проблемы с JUnit 4:

Возвращаясь к тестам, один из способов их исправить:

<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() );

Если вы не используете правило, вы можете запустить код в конкретном контексте Vert.x следующим образом:

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

Вы должны добавить то, что вы только что написали, в виде FAQ на сайт или где-нибудь еще.

Да, я согласен

@DavideD Очень признателен за ваше объяснение. Спасибо.

Я создал проблему для отслеживания этих изменений в документации / на веб-сайте: https://github.com/hibernate/hibernate-reactive/issues/751

Я собираюсь закрыть этот выпуск. Смело задавайте еще вопросы, еще чего-то непонятно.

Спасибо.

@DavideD Можно ли использовать следующий код, который вы упомянули ранее, с JUnit 5?

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

Да, это код Vert.x, а не JUnit.

Но это не эквивалентное расширение для JUnit 5:

<strong i="8">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();
Была ли эта страница полезной?
0 / 5 - 0 рейтинги