【问题标题】:Entity Manager per Thread design - how to implement每个线程设计的实体管理器 - 如何实现
【发布时间】:2012-07-02 10:57:53
【问题描述】:

我想知道如何为每个用户线程设计实现一个 JPA EntityManager。由于 EM 是轻量级对象,因此为每个用户线程创建它们不应该是开销。我要解决的问题是单个 JSP 页面,其中包含对后端服务的多个(并行)JSON/AJAX 调用(通过控制器)。

我有一个实体管理器(具有扩展的持久性上下文),带有 Open EM In View Filter。它确实工作得很好,但只有当每页有一个用户线程(例如,一个 json 调用)时,或者换句话说,当我以串行方式访问 em 时。 然而,当我从多个线程调用我的服务时,它并没有解决我的目的,因为 em 实例是共享的并且我得到了奇怪的错误(有时是对集合的共享访问,有时是关闭的连接,我相信这是预期的)。

我在 Spring 3 和 hibernate 3.5 上使用 JPA。我将实体管理器(扩展)注入到我的服务中,如下所示:

@PersistenceContext(type = PersistenceContextType.EXTENDED)
protected EntityManager em;

我的只读服务方法被注释为

<tx:method name="get*" read-only="true" propagation="SUPPORTS"/>

所有其他方法,都标注为

<tx:method name="*" propagation="REQUIRED" rollback-for="Exception"/>

我想避免应用程序管理 em,因此没有去注入 EntityManagerFactory。 另外,如果我选择将 EntityManager 注入到 spring 控制器中,当从两个线程并行调用同一个控制器时,我仍然会遇到问题!

有没有一种优雅的方式来实现对 em 的线程安全访问。我还想避免锁定任何实体对象,这会使事情进一步复杂化。

由于来自同一页面的多个 ajax 调用是现代 Web 应用程序中非常常见的设计,我相信必须有一种简单且声明性的方式来实现这一点(无需返回到使用拦截器等手动管理休眠会话)

【问题讨论】:

    标签: spring hibernate design-patterns jpa


    【解决方案1】:

    我不太明白你的问题。

    每个线程的实体管理器是默认行为,但您使用EXTENDED 明确覆盖它。将其配置为EXTENDED 有什么具体原因吗?如果没有,您只需将其删除:

    @PersistenceContext
    protected EntityManager em; 
    

    【讨论】:

    • 我将其设置为 EXTENDED 以确保无需任何额外努力即可加载所有惰性关联。否则我将不得不手动加载它们中的每一个(它们很多!)......例如user.organisation,user.roles,event。属性等现在可以无缝运行。
    • @Dilpa:只要您在处理请求时使用访问它们,Open EM in View 过滤器应该已经处理它。
    • 在这种情况下,我在加载惰性关联时得到的org.hibernate.LazyInitializationException: could not initialize proxy - no Session 的来源可能是什么。我确实有 OEMIV 过滤器。
    【解决方案2】:

    Spring 有一个 Thread 作用域,默认是禁用的(参见 4.5 Bean scopes 部分):

    线程范围的 bean
    从 Spring 3.0 开始,可以使用线程范围,但是 默认不注册。有关详细信息,请参阅 SimpleThreadScope 的文档。有关如何操作的说明 注册此或任何其他自定义范围,请参阅第 4.5.5.2 节,“Using a custom scope”.

    如果您激活范围,您只需将您的 entitymanagers 定义为 scope=thread

    【讨论】:

    • 有趣,我不知道这个。谢谢你。那么您是否建议我将我的 spring 控制器注册为线程范围(而不是现在的单例)?
    • @Dilpa 不,我不是建议。我多年来一直使用单例范围的实体管理器,几乎没有遇到过问题。但我正在为你的问题提供一个可能的答案,这是不同的;-)
    • 好的,我很乐意试一试。您能否详细说明如何将我的 entitymanagers 定义为 scope=thread ?还是您“建议”我将 emf 设为线程范围?
    • 这不会对我的申请造成巨大压力吗?
    • @Dilpa 我不这么认为。您可能可以配置应用程序在应用服务器中生成的线程数。大多数情况下,10 到 20 个线程就足够了
    【解决方案3】:

    这是使用 EM/Session 的最标准方式,并且有一些标准工具,例如 OpenSessionInViewFilter(或 Interceptor),当 HTTP 请求进入您的 servlet 容器时会创建一个会话。 或者它可以是一个 Spring Transactional 支持,它在 AOP 的帮助下创建一个会话。 这里的关键是使用已经存在的机制,或者,如果你有一些扩展,至少复制粘贴它们。 Spring 在 TransactionSynchronizationManager 的帮助下通过将资源绑定/取消绑定到线程来实现这一点。您可以查看 Spring 源代码或 here 是会话每次会话模式的示例,它也使用相同的方式将资源绑定到线程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-17
      • 2016-01-02
      • 2012-06-28
      • 2012-09-18
      • 1970-01-01
      • 2014-07-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多