JPA 性能优化或替代方案

Posted

技术标签:

【中文标题】JPA 性能优化或替代方案【英文标题】:JPA performance optimization or alternatives 【发布时间】:2016-01-12 00:49:10 【问题描述】:

我们目前处于一个对数据库读取性能要求很高的项目中。

我们目前正在使用 JPA(EclipseLink 实现),目前只是因为它提供了方便的数据库访问和列映射。

对于我们的查询,我们使用高度具体的 SQL 查询。我们还使用一个数据库(SAP HANA,内存中),因此不需要语言抽象。数据库访问非常快,我们目前的瓶颈确实是应用服务器,尤其是持久层。

结果集通常也不包含实体,因为实体是由上下文组成的。对我们来说,使用像下面这样的 @Id 字段没有意义,因为我们没有唯一的字段(只有组合,但定义 IdClass 开销太大)。

@Entity
public class Item 

    @Id
    public myField;


    // other fields...

如果我想运行类型化的本机查询,这似乎是由 JPA 强制执行的。这个假设是真的吗?目前我们还没有找到绕过 ID 映射的方法。

这些发现是否有效? 如果不是,我们如何才能使我们对 JPA 的使用性能更高(与普通 JDBC 相比存在显着延迟),同时也无需为结果类型定义 @Id(因为它在我们的情况下没用)? 如果是,是否有另一个 Java 库仅在 JDBC 之上提供一个最小层而没有太多延迟,提供比普通 JDBC 更方便的使用(具有列映射和所有这些好东西)。

谢谢!

用例:我们希望从数据库中传输历史 GPS 传感器数据。除了将其转换为 JSON 之外,我们还进行了一些转换/验证。这就是为什么我们实际上需要构建对象。所以我们基本上寻找的是一种将select语句的字段映射到属性的便捷方式。我希望这是有道理的。

【问题讨论】:

jOOQ 是使用 ORM 的一种替代方法。您能否举一些具体的例子来说明 JPA 与普通 JDBC 的性能问题? MyBatis 是另一个 【参考方案1】:

有很多关于提高 EclipseLink/JPA 性能的文章和博客,您可以查看,例如 EclipseLink Performance、JPA Performance Tuning 和 Optimizing the EclipseLink Application

最后,尽管这在很大程度上取决于您的特定用例以及您可能想要的任何未来用例。 JPA 旨在使 JDBC 之上的读写更容易和更易于维护,并增加了许多性能优势,例如缓存。如果您使用它的目的只是读取原始数据,那么额外的层可能是额外的开销,不会增加任何价值。让 JPA 从结果集中构建实体、维护缓存并监视更改只是让您的应用程序忽略它并获取原始数据并没有多大意义。

我不明白你为什么会有一个带有单个 myField 的 Item 表。应用程序如何使用它以及它与其他表和潜在实体的关系如何?

这种结构不是关系数据库和 ORM 的正常用例,但在 JPA 中仍有解决方法。数据可以由其他实体在元素集合中使用,甚至不被映射,并且使用直接通过 JDBC 层传递的本机 SQL 查询。 EclipseLink 本身有许多超越 JPA 的映射类型和选项,可能会根据您的用例使用。

【讨论】:

感谢您的回答。当然,我不想只映射一个字段,尽管这很明显,对此感到抱歉。我已经更新了我的帖子以更准确。 实体需要身份,就像任何数据库行一样。如果您计划在实体之间建立关系,JPA 将需要知道唯一标识实体的内容,并且它允许您在以后可能想要使用的缓存和性能增强功能。如果要转换为 JSON,则 ID 允许缓存和查找,并且 EclipseLink 的 moxy 组件可以将其重用于与 JSON 之间的转换,从而在更复杂的对象图中保持身份一致 如果您不打算使用 ID 或实体,那么您在实体上选择哪个字段或者它是唯一的都没有关系。将任何字段映射为 ID。然后,您可以在 JPA 查询中使用该实体来获取标量结果。或者,您可以使用所谓的构造函数查询来构建非实体对象,其形式为:“从项目 i 中选择新项目(i.myField,i.myField2)”,以便 JPA 为您构建对象。这些对象无论如何都不会被管理,因此不会被缓存等,只是基本的平面 DTO。 嗨,如果输入参数没有改变但输出应该改变,即使对于本机查询使用 eclipselink.query-results-cache=false,将 @Id 放在任何字段上都会产生奇怪的行为。它仍然会返回旧结果。我们最终尝试在保持唯一的字段组合上创建复合键(使用 IdClass),从而解决了问题。首先,这是我们不希望仅仅为了框架的目的而拥有的开销(因为它没有意义),其次,字段组合是唯一的情况并不总是如此。为此,我们已经手动分配了字段 旧结果?这应该只在您返回实体时发生,我提到如果您不打算设置正确的主键,您不应该这样做。使用构造函数查询不应返回实体,而是不由 JPA 管理或缓存的普通旧 java 对象。如果您要查询实体,最好选择一个唯一的 ID 并立即进行投资,因为这将使生活变得更轻松。如果您真的找不到一组唯一的字段,请使用整个类本身。

以上是关于JPA 性能优化或替代方案的主要内容,如果未能解决你的问题,请参考以下文章

[JavaEE - JPA] 性能优化: 如何定位性能问题

.NET性能优化-使用RecyclableMemoryStream替代MemoryStream

[JavaEE - JPA] 性能优化: 4种触发懒加载的方式

.NET性能优化-使用结构体替代类

简析Oracle性能优化可能出现的问题

Java HashMap 性能优化/替代