【问题标题】:Dropwizard @UnitOfWork with asynchronous database callDropwizard @UnitOfWork 与异步数据库调用
【发布时间】:2018-04-12 03:24:35
【问题描述】:

我认为这是一个常见问题,但经过一番搜索后,我找不到任何相关内容。

我遇到的问题是,在使用 @UnitOfWork 注释我的资源方法并在我的资源方法内部进行异步 DAO 调用时,我遇到了 No Hibernate Session bound to thread 异常。这种设计背后的想法是在单独的 I/O 线程上调用数据库,从而释放 Jersey 资源线程。

不幸的是,正如例外所说,这个RxIoScheduler-2 线程没有绑定休眠会话。

有什么建议吗?

【问题讨论】:

    标签: java multithreading hibernate rx-java dropwizard


    【解决方案1】:

    Hibernate Session 不是线程安全的,所以我们需要一个策略来获取当前线程的当前会话。这种策略称为CurrentSessionContext

    当前会话是我们通过此调用获得的会话:

    sessionFactory.getCurrentSession()
    

    Hibernate 可以配置各种当前会话策略。 @UnitOfWork 使用这种策略:

    hibernate.current_session_context_class = managed
    

    对于此策略,您应该通过显式调用

    将会话置于上下文中
    ManagedSessionContext.bind(session)
    

    因此,我们知道Session 不是线程安全的,您应该为单独的线程创建一个新会话并将该会话放入ManagedSessionContext。之后,您可以通过与@UnitOfWork 的端点方法相同的方式调用您的 DAO。

    请记住,您应该在关闭会话之前取消绑定

    ManagedSessionContext.unbind(factory)
    

    您可以使用此实用程序类为单独的线程创建会话:

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

    Throwables 来自guava

    可以这样使用

    List<Campaign> getCampaigns(SessionFactory factory, CampaignDao dao) {
        return HibernateSessionUtils.request(
                factory,
                dao::getCampaigns
        );
    }
    

    dao.getCampaigns()方法中可以获取会话

    sessionFactory.getCurrentSession()
    

    您可以使用Guice 在任何地方注入工厂。

    其他选项是使用UnitOfWorkAwareProxyFactory

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-10
      • 2016-01-02
      • 1970-01-01
      • 1970-01-01
      • 2015-05-13
      • 1970-01-01
      相关资源
      最近更新 更多