JPA存储库应该首选哪个CDI范围



如何为下面这样的JPA存储库确定合适的CDI范围?

@Transactional
public class CategoryRep extends EntityRepository<Integer, Category> {
    private static final long serialVersionUID = 856370976984333182L;
    public List<Category> getAllCategories() {
        // TODO
    }
    public List<Post> getAllPostsOfCategory(Integer categoryId) {
        // TODO
    }
    @Transactional(value = TxType.REQUIRES_NEW, rollbackOn = RuntimeException.class)
    public void createCategory(final String name, final String description)
            throws DaoJpaException {
        // TODO
    }
}

我只能想到两个CDI范围:

  1. @SessionScope:对我来说,这似乎是最合适的范围,因为单个实例专用于活动会话
  2. @依赖:这也是合理的,因为这样的实例将适合于将被注入的对象的生命周期

在我看来,所有其他CDI范围都不合适:

  1. @ApplicationScoped:由于应用程序范围的存储库每次只创建一次,因此类似于:entityManager.clear()的调用将导致所有当前会话的所有实例也将分离。此外,这个单独的存储库必须处理所有传入的请求。这个范围是否适合只读存储库
  2. @RequestScope:我认为不需要为每个传入的请求创建一个新的存储库实例
  3. @ConversionScoped:转换通常在GUI层强制执行。如果我希望存储库在转换结束后消亡,我可以将其定义为@Dependent

那么,对于这个问题,有什么已知的最佳实践吗?

描述的所有选项

  • 会话范围实际上没有意义,因为您的存储库应该是无状态的,因此会话对它没有任何意义(尽管它可以解决并发问题
  • 从属作用域可能是一个不错的选择,但它可能会导致内存泄漏(您永远无法确定将从内存中删除哪些从属对象)
  • 会话范围也没有任何意义,它与会话范围的情况相同

所以我会选择

  • 请求范围——我认为这是最好的选择,它本质上是无状态的,因此可以避免任何并发问题。也不用担心性能,在新JVM中非常非常快地创建新对象
  • 应用程序范围也是一个不错的选择,但是您需要担心并发问题(多个客户端同时调用同一方法)

所以,如果我是你,我会选择请求范围存储库,这是最简单的选择,你可以通过这种方式避免所有问题。

您应该使用@ApplicationScoped。

每个请求都应使用EntityManager,而不应重复使用。

在请求时,您创建entityManager,当它完成提交或回滚时。

@Dependent将具有与其"host"相同的作用域,如果将其注入@RequestScoped,则bean将具有相同的作用。

@SessionScoped应仅用于小数据(如用户登录和权限)。

最新更新