Dropwizard @UnitOfWork与异步数据库调用 [英] Dropwizard @UnitOfWork with asynchronous database call
问题描述
我想这是一个普遍的问题,但是经过一番搜索,我找不到任何相关的东西.
I imagine that this is a common problem, but after some searching I wasn't able to find anything relevant.
我遇到的问题是,在使用 @UnitOfWork
注释资源方法时以及在资源方法内部时,出现了 No Hibernate Session绑定到线程
异常的问题.,进行异步DAO调用.这种设计的思想是在一个单独的I/O线程上进行数据库调用,以便释放Jersey资源线程.
The problem I'm having is that I'm getting a No Hibernate Session bound to thread
exception when annotating my resource method with @UnitOfWork
and inside my resource method, making an asynchronous DAO call. The idea behind this design is to make the database call on a separate I/O thread so that it frees up the Jersey resource thread.
不幸的是,如异常所示,此 RxIoScheduler-2
线程没有绑定的休眠会话.
Unfortunately, as the exception says, this RxIoScheduler-2
thread doesn't have a hibernate session bound to it.
有什么建议吗?
推荐答案
休眠 Session
不是线程安全的,因此我们需要一种策略来获取当前线程的当前会话.这种策略称为 CurrentSessionContext
.
Hibernate Session
is not thread safe, so we need a strategy how to get the current session for the current thread. Such strategy is called CurrentSessionContext
.
当前会话是我们通过此调用获得的会话:
The current session is a session which we get by this call:
sessionFactory.getCurrentSession()
可以为Hibernate配置各种当前会话策略. @UnitOfWork
使用以下策略:
Hibernate can be configured with various current session strategies. @UnitOfWork
uses this strategy:
hibernate.current_session_context_class = managed
对于这种策略,您应该通过显式调用
For this strategy you should put a session to the context by an explicit call of the
ManagedSessionContext.bind(session)
因此,我们知道 Session
不是线程安全的,因此您应该为单独的线程创建一个新会话,并将该会话放入 ManagedSessionContext
中.之后,您可以使用与 @UnitOfWork
相同的终结点方法来调用DAO.
So, as we know a Session
is not thread safe, you should create a new session for a separate thread and put that session in the ManagedSessionContext
. After that you can call your DAO by the same way as in the endpoint methods with @UnitOfWork
.
请记住,您应先关闭会话,然后再使用
Keep in mind that you should unbind the session before closing it with
ManagedSessionContext.unbind(factory)
您可以使用此实用工具类为单独的线程创建会话:
You can use this utility class to create a session for a separate thread:
public final class HibernateSessionUtils {
private HibernateSessionUtils() {
}
public static void request(SessionFactory factory, Runnable request) {
request(factory, () -> {
request.run();
return null;
});
}
public static <T> T request(SessionFactory factory, Supplier<T> request) {
Transaction txn = null;
Session session = factory.openSession();
try {
ManagedSessionContext.bind(session);
txn = session.beginTransaction();
T result = request.get();
commit(txn);
return result;
} catch (Throwable th) {
rollback(txn);
throw Throwables.propagate(th);
} finally {
session.close();
ManagedSessionContext.unbind(factory);
}
}
private static void rollback(Transaction txn) {
if (txn != null && txn.isActive()) {
txn.rollback();
}
}
private static void commit(Transaction txn) {
if (txn != null && txn.isActive()) {
txn.commit();
}
}
}
来自 guava
的
Throwables
.
可以通过这种方式使用
List<Campaign> getCampaigns(SessionFactory factory, CampaignDao dao) {
return HibernateSessionUtils.request(
factory,
dao::getCampaigns
);
}
在 dao.getCampaigns()
方法中,您可以获取会话
In the dao.getCampaigns()
method you can get the session
sessionFactory.getCurrentSession()
您可以使用 Guice
将工厂注入各地.
You can inject the factory everywhere using Guice
.
其他选项是使用 UnitOfWorkAwareProxyFactory
.
这篇关于Dropwizard @UnitOfWork与异步数据库调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!