每个线程设计的实体管理器 - 如何实现

时间:2012-07-02 10:57:53

标签: spring hibernate design-patterns jpa

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

我有一个实体管理器(具有持久性上下文EXTENDED),以及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控制器,那么当从两个线程并行调用相同的控制器时,我仍会遇到问题!

是否有一种优雅的方式来实现对线程的安全访问。我还想避免锁定任何实体对象,这会使事情变得更加复杂。

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

3 个答案:

答案 0 :(得分:2)

我不太明白你的问题。

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

@PersistenceContext
protected EntityManager em; 

答案 1 :(得分:0)

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

  

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

如果您激活范围,则可以将实体管理员定义为scope=thread

答案 2 :(得分:0)

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