Dropwizard @UnitOfWork与异步数据库调用 [英] Dropwizard @UnitOfWork with asynchronous database call

查看:70
本文介绍了Dropwizard @UnitOfWork与异步数据库调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想这是一个普遍的问题,但是经过一番搜索,我找不到任何相关的东西.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆