我发现JPA或类似技术不鼓励DAO模式。

42
我发现JPA或类似的技术并不支持DAO模式。我不知道为什么,但是我感觉特别是与服务器管理的JTA管理器一起使用时,这种情况更加明显。
在充分使用DAO模式后,我开始设计基于JPA的应用程序,但是我觉得它并不适合。在我看来,我倾向于失去JPA的许多功能。
假设您使用悲观锁定发出查询并从DAO方法返回实体列表。当事务结束且锁定消失(与由服务器管理的JTA管理器有关的一种情况)时,就没有必要了。虽然有有效的情况。
另一个例子更加琐碎。假设您发出查询以获取某个具有延迟加载一对多关联其他实体的实体。在DAO方法返回后,事务结束。惰性加载不再起作用,您只会得到null或其他内容。为了解决这个问题,我们手动进行急切加载。我们可以执行类似于a.getBList().size()的操作。
因此,在我的看法中最好不要专门制作DAO,而是在业务bean中进行操作,这样您就能够利用那些有用的功能。或者可以将ORM API视为DAO /数据层本身。因此,我们不需要再创建一个DAO。
你们认为呢?
注意:我并不是说DAO模式已经过时了。事实上,它取决于具体情况。
3个回答

48

对于简单的应用程序,我认为直接从EJB中使用EntityManager并跳过DAO模式(我已经厌倦了写太多的代码)是没有问题的。我的感觉确实是这就是JPA和Java EE API所鼓励的。但对于更复杂的应用程序(例如从存储过程、平面文件等访问数据),仍然可以证明它是有必要的。所以你是正确的,这取决于具体情况 :)

您将在InfoQ上的《JPA是否已经杀死了DAO?》中找到其他启发性观点,但您不会对内容和结论感到惊讶,可以概括为:对于标准数据访问,您不再需要DAO模式,但是在某些更复杂的情况下可能仍然需要它,但我们没有它也能生活得更好。


我倾向于同意,如果没有特定的想法,就没有理由创建DAO层。甚至是通用的DAO,更不用说为实体创建单独的DAO类了。 - Bozho
我一直在苦苦寻找一种好的方法来测试我的Java EE JAX-RS/JPA代码,而且试图获得可行的“容器内测试”解决方案一直是一场噩梦。主要问题是尝试从测试中注入@Context PersistenceContext。我认为使用@EJB Dao以及从测试中调用并设置Dao的构造函数将会更加简洁。 - Matthew Cornell

34
如果您不把DAO本身定义为事务性的,那么就不会出现这些问题。
服务层应该是事务性的,因为事务应该跨越多个操作。把每一个插入/更新放在一个事务中并不是最好的情况。
使用Spring可以很容易地实现这一点。如果没有它,你也许需要在DAO中再次包含事务逻辑——即dao.beginTransaction()dao.commitTransaction(),然后从服务层使用它们。
据我所知,你建议在服务类中直接使用EntityManager可能比使用包装器DAO类更好。但我有一个原因不同意。在你的服务类中使用DAO类(最好是接口),你完全不需要依赖JPA API。你不需要构造Query对象或类似的东西。这可能不会带来很大的优势,但你会认为这是最佳实践。而你只需改变DAO类就可以轻松地切换到纯JDBC、纯文本、XML或其他方式。
虽然经常被广泛用作将某些东西抽象到另一层的示例,但这通常只是过度设计。但有时候,所有数据库访问操作都通过一个地方进行,这意味着你可以添加日志记录、访问级别检查等等。(是的,有时DAO并不是特别适合做这个).
所以最终回到你的观点——这取决于情况。

7
在你的服务类中使用 DAO 类,你就不需要依赖于 JPA API。如果你不这样做,你就会依赖于 EJB 3 - 但这有什么问题呢?说实话,我不在乎依赖于一个标准 API。 - Pascal Thivent
3
当然,你仍然依赖于它因为你在使用它,这没有问题。但我的观点是,你可以轻松更改持久性机制而无需修改所有类,因为它们仅依赖于DAO接口。 - Bozho
9
我理解你的观点,但我在过去10年中并没有经常看到这种情况发生,因此认为这种事件是一种神话。 - Pascal Thivent
1
+1,绝对正确。即使在JPA环境中,DAO模式仍然相关,因为您的服务层是事务性的,并且一个事务可以跨多个DAO调用。 - semberal
1
我也不确定 :) 但是添加日志记录、访问检查等操作也是可能的。现在DAO并不是执行这些操作的最佳位置。所以最终结果取决于具体情况 :) - Bozho
显示剩余8条评论

3

DAO是用于设计层面的,而JPA则是一种“官方”的数据访问函数包装。 JPA不会试图取代DAO——它可以使DAO更容易实现,甚至简单到可以被忽略的地步。但是,如果没有DAO层,设计优势将不存在。

当然,对于“简单”的项目,可以忽略它。如果项目足够“简单”,很多东西都可以被“忽略”。


艾尔顿:我完全同意你的意思,没有任何条件。然而,我想强调分层并不是获得良好设计的唯一手段。因此,我不能绝对同意你的这个说法,“没有分层就没有设计的所有好处”。希望你能理解我的观点。 - Adeel Ansari
好的。Dao层存在已经有很长时间了,有其设计上的好处。没有Dao层,这些设计上的好处肯定会消失。也许在你的情况下你不关心这一点,这就是为什么你觉得它已经过时了。我认为你的问题实际上是关于Dao带来了什么,以及你是否需要Dao所带来的东西。对我来说,“Dao”层永远不会消失。当你将EntityManager注入到业务层时,你的业务层也在执行Dao层的工作。你可以将这些层结合在一起,根据你的需求选择更好的解决方案。再次强调,这取决于具体情况,没有“绝对”的解决方案。 - Elton
Elton:请注意,即使在你来到这里之前,结论仍然是“取决于情况”。我从未觉得DAO是一种过时的模式,请仔细阅读问题。我试图非常明显地表达这一点。 - Adeel Ansari
是的,我添加评论的原因是为了补充一点,JPA是功能性的,而DAO是设计角度。虽然我没有明确说“取决于”,但我用另一种方式表达了“取决于”。我并不反对任何人,我想。 - Elton
1
在架构上,把 DAO 称作包装器是一种很妙的说法。DAO 是一层包装 API 的抽象,它是与数据库进行交互的接口。这可能是 JPA(EntityManager)具有某些 ORM 优势的实现,也可以是仅使用 JDBC。 - 8bitjunkie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接