JavaEE6 DAO:应该是@Stateless 还是@ApplicationScoped?

Posted

技术标签:

【中文标题】JavaEE6 DAO:应该是@Stateless 还是@ApplicationScoped?【英文标题】:JavaEE6 DAO: Should it be @Stateless or @ApplicationScoped? 【发布时间】:2011-03-14 11:31:19 【问题描述】:

我目前正在创建一个 EJB3 数据访问类来处理我的 Java EE 6 应用程序中的所有数据库操作。现在,由于 Java EE 6 提供了新的 ApplicationScoped 注释,我想知道我的 EJB 应该有什么状态,或者它是否应该是无状态的。

让DAO 成为@Stateless Session Bean 还是@ApplicationScoped Bean 会更好吗? @Singleton 呢?这些与 DAO 相关的选项之间有什么区别?

编辑: 我正在使用带有完整 Java EE 6 平台的 Glassfish 3.0.1

【问题讨论】:

【参考方案1】:

让 DAO 成为 @Stateless Session Bean 还是 @ApplicationScoped Bean 哪个更好? @Singleton 呢?这些与 DAO 相关的选项之间有什么区别?

我不会将无状态会话 Bean 用于 DAO:

    EJB 由容器池化,因此如果每个池有 N 个实例和数千个表,您只会浪费资源(更不用说部署时的成本)。

    将 DAO 实现为 SLSB 会鼓励 EJB 链接,从可扩展性的角度来看,这不是一个好的做法。

    我不会将 DAO 层绑定到 EJB API。

EJB 3.1 中引入的@Singleton 可以使事情变得更好,但我仍然不会将 DAO 实现为 EJB。我宁愿使用 CDI(也可能是自定义原型,例如,参见 this article)。

或者我根本不会使用 DAO。 JPA 的实体管理器是 Domain Store 模式的一个实现,并且在 DAO 中包装对域存储的访问不会增加太多价值。

【讨论】:

感谢您的回复!我不想在这里讨论 DAO 是否有意义。对我来说,使用一个是有意义的。至少在Seam 3 Persistence Module 准备好投入生产之前;)所以你说我不应该将DAO 层绑定到EJB API。但是交易和安全呢?如果不是用于数据库操作-> DAO,我将在哪里使用这些服务?这些服务不是由 CDI 提供的,至少不是像常规 JavaEE6 容器那样管理的方式。或者我应该混合使用 CDI 和 EJB? >EJBs are pooled by the container so if you have N instances per pool and thousands of tables - 1. 如果您有数千个表和数千个实体,您可能需要修改您的设计。除此之外,EJB 实例通常是按需创建的,而不是事先创建的,当然也不是一次全部用于池容量。那么,即使创建数千个实例,数千个实例的内存需求也只有 1 兆字节,这完全是微不足道的。启动应用服务器时会产生少量额外费用(我认为这就是部署时间的意思) 2.为什么 DAO 鼓励“链接”???在这种情况下,这甚至意味着什么?如果您的意思是一个 bean 调用另一个 bean,那么这在 EJB 中实际上是非常有效的(只要我们谈论的是本地调用,这当然应该在这里使用)。注入非常便宜(代理被注入),并且对其他 bean 的调用显式共享上下文资源,除非这被显式禁用(这是非常罕见的)。 3.这显然是你的意见,但我实际上绝对会这样做。它为您提供了轻松注入实体管理器和方法自动创建或加入现有事务的好处。 >wrapping access to a Domain Store in a DAO doesn't add much value - 对于纯粹的 CRUD,实体管理器几乎可以直接使用,但实际上,当您需要在保存/更新。对于删除,您将必要的样板代码放在 DAO 中,因为实体管理器无法删除未附加的实体。此外,DAO 可以包含对相关实体的查询的访问权限(服务会做同样的事情,但另外会进行访问检查,而 DAO 则不会)【参考方案2】:

经过重新思考,DAO 似乎并不是我想做的事情的正确名称。正如 Pascal 所说,也许它真的是一个 Facade。 我刚刚找到了 Netbeans Petstore 示例 - 一个 JavaEE6 示例应用程序,请参阅 here - 他们有一个 ItemFacade 负责从数据库中查找/创建/删除实体。它是一个无状态会话 Bean。看起来像这样:

@Stateless
public class ItemFacade implements Serializable 
    @PersistenceContext(unitName = "catalogPU")
    private EntityManager em;

    public void create(Item item)  ... 
    public void edit(Item item)  ... 
    public void remove(Item item)  ... 
    public Item find(Object id)  ... 
    public List<Item> findAll()  ... 
    public List<Item> findRange(int maxResults, int firstResult)  ... 
    public int getItemCount()  ... 

所以作为一个结论,我不再调用我的 DAO DAO,而只是例如 PersonEJB(我认为“PersonFacade”可能会被误解)并将其设为 @Stateless,因为我认为 Netbeans 示例也可以考虑- 设计。

【讨论】:

这是我回答的最后一部分:根本没有 DAO,session facade 用于事务控制和安全性,SLSB 是 Java EE 中的自然候选者。现在,我不得不说,首先,上面的答案实际上并没有回答你的初始问题,其次,(实际上)改写你自己的问题以匹配你的答案并不会激励我花更多时间对此。无论如何,祝你好运。 更改了接受的答案。你现在快乐吗? ;) 你说得对,这个答案与我最初的答案无关。感谢您的帮助。【参考方案3】:

@帕斯卡: 在我看来,我的 DAO 对事务或安全性不“负责”,因为容器管理这些服务。我只是在我的 DAO 中注释方法(仅出于安全考虑,因为事务是自动处理的)。注释已经“责任”了吗?

好的,所以你让我重新考虑我的设计。希望它没问题并且不太离题,但也许它会有所帮助 - 这就是我今天使用 JEE6 的方式:

JSF 访问 CDI Bean, CDI Bean 访问 DAO-EJB 做“业务逻辑” 所以目前我唯一的“业务逻辑”正在执行 CRUD,稍后我将为异步方法或计时器服务等关键任务添加一些其他 EJB。 我的 DAO 是通用的,使用 JPA2 Criteria Query 进行类型安全查询(根本没有字符串) 我知道我不需要用于持久/更新/删除的 DAO(太简单了),但我的查询需要它;所以我把它们放在一起

这种方法有问题吗?

【讨论】:

以上是关于JavaEE6 DAO:应该是@Stateless 还是@ApplicationScoped?的主要内容,如果未能解决你的问题,请参考以下文章

Java EE 6 - JSF 控制器

Java EE 6:JSF 与 Servlet + JSP。我应该费心学习 JSF 吗?

Service Fabric 中的 Stateless Worker 服务在同一进程中重新启动

DAO 层应该如何实现?一张表 DAO 还是多表 DAO?

DAO(又名存储库)是不是应该进行单元测试?

注入 Guice 的 DAO 应该是单例吗?