你好,
到目前为止,在使用 Hibernate 反应式 API (1.0.0.CR4) 时,Vertx 只是对我隐藏。 但是我必须公开一个 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
我尝试以多种不同的方式重构代码,但没有成功使其运行。
你能给我你的建议如何正确地做到这一点吗?
谢谢。
你好,
会话的问题在于它不是线程安全的,在不同的线程中使用它可能会导致难以调试的问题。 此外,创建新会话时会绑定到 Vert.x 上下文,之后需要在同一上下文中使用。
当使用SessionFactory#withTransaction
和SessionFactory#withSession
时,这通常由 Hibernate Reactive 处理。
您的测试不起作用,因为它们运行在 JUnit 线程中,而不是 Vert.x 线程中。
在 JUnit 4 中解决此问题的一种方法是通过库io.vertx:vertx-unit:4.0.3
包含的规则:
<strong i="13">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();
但这还不够,您还需要确保会话绑定到规则定义的同一个 Vert.x 上下文。
通常,实现此目的的方法是创建自定义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 );
或者,您可以使用JDK的
org.hibernate.reactive.vertx.VertxInstance
的文本文件
/META-INF/services/
VertxInstance
接口的类的路径:
org.myproject.MyVertxProvider
现在 Hibernate Reactive 将在需要 Vert.x 实例时调用MyVertxProvider
实例,并且如果您的代码在相同的 Vert.x 上下文中运行,则一切正常。
回到测试,修复它们的一种方法是:
<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
});
您应该将刚刚写的内容作为常见问题添加到网站或其他任何地方。
好,我会的
@DavideD非常感谢您的解释。 谢谢。
@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();
最有用的评论
好,我会的