【问题标题】:How to get Hibernate session inside a Hibernate Interceptor?如何在休眠拦截器中获取休眠会话?
【发布时间】:2009-01-08 11:14:59
【问题描述】:

如何在 Hibernate 拦截器中获取 Hibernate 会话?

我正在尝试使用 Hibernate 通过组织 ID 透明地强制执行数据访问。 我设置了一个全局过滤器来按组织 ID 过滤所有查询。 现在,我需要在保存/更新之前使用实体拦截器在所有实体上设置组织 ID。

组织id来自HttpSession

我在 Hibernate 会话中将组织 ID 设置为过滤器属性,我想在我的拦截器中检索它并用于所有插入和更新。 问题是我似乎无法访问拦截器内的会话。有什么解决方法吗?

【问题讨论】:

    标签: java hibernate orm


    【解决方案1】:

    你可以,但我会使用一个简单的 POJO 来保持干净分离。请记住,存储在单例中的值只能由处理 servlet 请求的同一线程访问,因此,如果您正在执行任何异步操作,则需要考虑这一点。这是一个超级基本的实现:

    public class OrgId {
       public static ThreadLocal<Integer> orgId = new ThreadLocal<Integer>();
    }
    

    由于组织 ID 驻留在会话中,您可以像这样在早期的 servlet 过滤器中设置 ThreadLocal 的值(没有太多错误检查):

    public class OrgIdFilter implements Filter {
       public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain) throws java.io.IOException, javax.servlet.ServletException {
          int orgId = 0;
          HttpServletRequest req = (HttpServletRequest) servletRequest;
          HttpSession session = req.getSession();
          orgId = Integer.parseInt(session.getAttribute("OrganizationalIdAttr"));
          try {
             OrgId.orgId.set(orgId);
             filterChain.doFilter(servletRequest, servletresponse);
          } finally {
             OrgId.orgId.set(null); // Important to clear after request !!
          }
       }
    }
    

    这假设在调用过滤器时 orgId 在会话中,但如果不是,您就会明白......

    然后在您的拦截器(或几乎任何地方)中,您可以通过以下方式获取线程的当前 orgId:

    OrgId.orgId.get();   // Might be null.....
    

    这里的一个潜在问题是所有这些组件(过滤器、OrgId 和拦截器)都需要由同一个类加载器加载,以确保 OrgId 类是有效的单例,否则,会有多个 ThreadLocal 实例挂在它周围将无法始终如一地工作,或者根本无法工作。不用说,所有这些都需要在同一个虚拟机中进行。

    我不确定这是否是解决此问题的最简洁方法,但它确实可以将您的 orgId 带到您需要的地方。

    【讨论】:

      【解决方案2】:

      如果您只需要组织 ID,您可以将其放在静态 ThreadLocal 中,然后在拦截器中访问它。

      另一方面,如果您对获取会话一无所知,这取决于您的环境,您可以放弃拦截器并使用org.hibernate.event.FlushEntityEventListener,这似乎更符合您的需求.你可以像这样得到会话(粗略的伪代码):

      FlushEntityEventListener.onFlushEntity(FlushEntityEvent event)
      EntityEvent entityEvent = event.getEntityEntry();
      EntityPersister persister = entityEvent.getPersister();
      SessionFactoryImplementor sessionFactoryImplor = persister.getFactory();
      Session session = sessionFactoryImplor.getCurrentSession();
      

      来自Hibernate 3 On Line Docs事件系统可以作为拦截器的补充或替代使用。

      【讨论】:

      • 你的意思是说我可以在我的 Servlet/Controller 中有一个 ThreadLocal 变量并在 Hibernate 拦截器中获取它?我如何访问 ThreadLocal 变量。它应该在 Servlet 中是公共静态的吗?
      • Btw Ev​​entSource 可从 FlushEntityEvent 访问是 Session 的子接口,因此您无需遍历 EntityPersister 等
      【解决方案3】:

      当你创建你的Interceptor时,如果你可以给它提供一个SessionFactory的引用,你可以使用SessionFactory#getCurrentSession

      【讨论】:

        【解决方案4】:

        Interceptor 可以做成 BeanFactoryAware 和 SessionFactory 可以使用可以获取当前会话的 bean factory 来获取。

        由于循环依赖和让拦截器知道 Spring 容器,这似乎是一个糟糕的设计,我按照 Nicholas 的建议使用了 ThreadLocal

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-25
          • 1970-01-01
          • 2019-05-16
          • 1970-01-01
          • 2014-12-20
          相关资源
          最近更新 更多