【问题标题】:Should I always retrieve full object from a database?我应该总是从数据库中检索完整的对象吗?
【发布时间】:2012-06-08 09:21:17
【问题描述】:

这是一个非常简单的问题,适用于使用 java 编程 Web 界面。说,我没有使用 ORM(即使我正在使用),假设我的应用程序中有这个 Car (id,name, color, type, blah, blah) 实体,我有一个 CAR 表在数据库中表示该实体。所以,假设我只需要更新一堆汽车上的一部分字段,我知道典型的流程是:

  1. DAO 类 (CarDAO) - getCarsForUpdate()
  2. 遍历所有 Car 对象,仅将颜色更新为绿色或其他颜色。
  3. 另一个 DAO 调用 updateCars(Cars car)。

现在,对于一个简单的选择和更新查询,这不是有点绕圈子吗?在上面的第一步中,我将从数据库中检索整个对象数据:“select id,name,color,type,blah,blah.. where ..from CAR”而不是“从 CAR 中选择 id、color ...”。那么为什么我在发布 DAO 调用时要检索那些额外的字段,我永远不会使用“颜色”以外的任何东西?这同样适用于最后一步 3。或者,假设我只查询 id 和颜色(选择 id、color)并创建一个仅填充 id 和颜色的汽车对象 - 这完全可以,不是吗? Car 对象还是贫血?

这一切(面向对象)是不是有点假?

【问题讨论】:

    标签: java oop database-design architecture orm


    【解决方案1】:

    首先,如果 RDBMS 可以处理您的查询,我更愿意接受它。原因是您不希望 JVM 完成所有工作,尤其是在运行企业应用程序时(并且您有许多并发连接需要相同的资源)。

    如果您特别想更新数据库中的对象(例如将汽车颜色设置为绿色),我建议您使用类似 SQL 的 SQL

    UPDATE CAR SET COLOR = 'GREEN';
    

    (注意我没有使用 WHERE 子句)。这会更新 ALL CAR 表,我不需要提取所有 Car 对象,调用 setColor("Green") 并进行更新。

    事后看来,我想说的是应用工程知识。您的 DAO 应该简单地进行快速选择、更新等操作,并让所有 SQL“工作”由 RDBMS 处理。

    【讨论】:

    • 更新整个表格没有意义,当我只想根据某些条件(where 条件)更新一堆汽车时,会吗?
    • 问题真的是......为什么我们喜欢表现得好像我们正在从 RDBMS 读取到一个对象,而这两个东西是完全不同的空间?表格不是对象,对象也不是表格。
    • @Jay,你能写一个 SQL 查询来处理你的情况吗?如果可以,请让 RDBMS 执行查询,而不是在 Java 中拉取它并自己更新。
    • 相似之处在于两个空间都有关系。 RDBMS 使用键,而对象使用继承、组合等作为对象之间的关系。困难的工作是将它们在这两个空间之间关联起来。这就是软件工程的用武之地。它不是关于编码,而是关于工程。 :-)
    • 好的。所以你是说,做类似“更新 CAR set COLOR=GREEN where ID in (?,?,?,?,?,?,?,?,?,?,?) ?这不会影响性能吗?
    【解决方案2】:

    根据我的经验,我可以说的是: 只要您不进行连接操作,即仅从同一个表中查询列,您获取的列数几乎不会对性能产生任何影响。真正影响性能的是获得的行数和 where 子句。获取 2 或 20 列的变化非常小,您不会看到任何差异。 更新也是一样

    【讨论】:

    • “几乎没有” - 这真的取决于您要获取的表和数据,不是吗?网络性能如何?获取大量文本怎么样?它会影响从远程数据库获取内容的应用程序的性能吗?
    • 您正在尝试做的是过度优化。仅获取和更新特定字段会使您的生活和应用程序变得非常复杂。它不会给你带来任何好处。当然,如果你有非常具体的情况,比如有一个巨大的文本列,你应该设计一个具体的解决方案。但这是一个不同的问题:)
    • 我会告诉你减少选定列的数量通常对性能的影响有限这一事实。无论如何,DBMS 基本上都会一口气获取整行。如果您有非常大的列,我看到的唯一区别是网络传输速度。见stackoverflow.com/questions/2194424/…。如果您确实在上下文中看到对象加载的改进,您可以实现大型列(BLOB、CLOB 等)的延迟加载,但这会迫使您重写 ORM 已经开箱即用的东西。
    【解决方案3】:

    我认为在某些情况下,请求对象字段的子集很有用。如果您有大量的列,或者如果有一些大的BLOB 列在水合后会影响性能,这可能会提高性能。尽管数据库通常会在匹配时读取整行信息,但通常会将BLOB 和其他大型字段存储在不同的位置,并且对 IO 的要求不高。

    如果您正在遍历一个大表并进行某种处理,这也可能是有意义的。尽管在单行上节省的成本可能微不足道,但在一张大表中可能是可以衡量的。

    另外,如果您只使用索引中的字段,我相信该行本身永远不会被读取,它将使用索引本身的字段。但是,不确定在您的示例中是否会为 color 编制索引。

    综上所述,如果您只保留相对简单的对象,没有 BLOB 或其他大型数据库字段,那么这可能会变成过早的优化,因为查询处理、行 IO、JDBC 开销和对象创建很可能与水合行中的字段子集相比,这需要更多的时间。将数据库对象转换为最终的 Java 类通常只是每个查询负载的一小部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多