给定:简单的JSF web应用程序(没有Seam), JSF bean调用几个EJB,这些EJB反过来加载和持久化JPA实体。我想要的是为ejb使用@Singleton
注释并注入EntityManager
而不是 EntityManagerFactory
:
@Singleton
public class MyEJB {
@PersistenceContext(unitName = PERSISTENCE_UNIT_NAME)
protected EntityManager em; // not EntityManagerFactory
}
Spec说@Singleton
是线程安全的,支持并发性和事务属性,这(从我的pov)使得它可以安全地从JSF bean调用。我还期望性能方面的好处,因为EntityManager
不会为每个调用重新创建,而且它的内部缓存能力。
我在这里主要关注的是在JPA实体上创建/更新操作,当我有几个单例时,结果是相同的长寿entitymanager计数。
- 如果一个单例更新一个JPA实例会发生什么更改填充到其他单例吗?
- 由于我无法关闭实体管理器,我需要冲洗它吗每个实体更新?
- 如果这几个单例共享同一个实体会更好吗经理吗? 我只看到几个这样设计的例子。为什么?有严重的吗?缺点呢?
提前感谢!
我也期望性能的好处,因为EntityManager不被重新创建每个调用和它的内部缓存能力。
使用单例可以节省一些内存,但是在应用程序中到处使用它可能会使它实际上变慢,因为只有一个EJB来服务应用程序的各种用户的所有并发请求,容器锁定对EJB的访问,当它忙于服务一个请求时,它不能服务另一个请求。但是,使用锁类型(即@Lock(WRITE)
和@Lock(READ)
)可以在一定程度上缓解这种情况。
当您想要使用EJB计时器周期性地执行一段代码,或者周期性地更新缓存等时,单例非常有用。
如果一个单例更新了一个JPA实例,这些更改如何填充到其他单例中会发生什么?
应该与非单例ejb的行为方式没有任何不同。
由于我无法关闭实体管理器,是否需要在每次实体更新时刷新它?
如果使用CMT,则不需要。在每个事务结束时,所有内容都将自动刷新。
如果这几个单例共享同一个实体管理器会更好吗?
在我看来是不成熟的优化。就让集装箱给你注射EM吧。
我只看到几个这样设计的例子。为什么?有什么严重的缺点吗?
已经解释。
关于更改单例ejb的LockType,我想提到一件事。虽然一般来说这听起来是个好主意,但您应该记住,entitymanager等资源不是线程安全的,因此应该提供适当的并发访问控制。您可以用@Lock(WRITE)注释访问非线程安全资源的方法,但是如果您的单例EJB的几乎所有接口方法都访问此类资源,那么您将遇到与完全写锁定的方法几乎相同的情况。另一种选择是使用Bean并发管理和手动细粒度同步,但这也是一个值得商榷的决定。
因此,我一般更喜欢无状态ejb而不是单例ejb,并在特定情况下使用后者。