简体   繁体   English

在 JPA/Hibernate 中执行只读操作的最佳实践是什么?

[英]What is best practice for performing read only operations in JPA/Hibernate?

Section 28.6 of the hibernate manual mentions that you shouldn't use entity queries for read only fetching, as they suffer from requesting too much data. hibernate 手册的第28.6节提到您不应该使用实体查询进行只读获取,因为它们会因请求太多数据而受到影响。

This makes sense, we've seen that complicated domain models can lead to very long running queries, especially when working with table views.这是有道理的,我们已经看到复杂的域模型会导致运行时间很长的查询,尤其是在使用表视图时。

The manual goes on to note:该手册继续指出:

For read-only transactions, you should fetch DTO projections because they allow you to select just as many columns as you need to fulfill a certain business use case.对于只读事务,您应该获取 DTO 预测,因为它们允许您访问 select 与满足特定业务用例所需的列一样多。

But AFAIK JPA doesn't provide a good way for fetching these projections, you are left playing with the criteria builder, which we've found is verbose, brittle and every so often fails to work properly (implementation is hard).但是 AFAIK JPA 并没有提供获取这些预测的好方法,您只能使用标准构建器,我们发现它冗长、脆弱并且经常无法正常工作(实施起来很困难)。

Indeed looking at various posts on SO shows that lots of people are using entities for reads.事实上,查看 SO 上的各种帖子表明,很多人正在使用实体进行读取。 So the questions I pose are as follows:所以我提出的问题如下:

  1. Is avoiding read-only entity queries common in real world enterprise applications, I get the feeling it isn't.正在避免在现实世界的企业应用程序中常见的只读实体查询,我觉得它不是。
  2. If it is, what tools are people using to make this bearable, a seperate query dsl comes to mind, jOOQ?如果是,人们使用什么工具来使这个可以忍受,一个单独的查询 dsl 浮现在脑海中,jOOQ?
  3. Are there any resources where best practices are laid out for the architecture of a Spring app with a connection to a persistence layer (I'm thinking of other complicated issues that could cause problems, such as transaction management), it seems everyone seems to take an ad-hoc approach.是否有任何资源为与持久层连接的 Spring 应用程序的架构制定了最佳实践(我正在考虑可能导致问题的其他复杂问题,例如事务管理),似乎每个人都接受一种特别的方法。

You have to understand that there is no definitive answer and everyone will give you different suggestions/advice based on their experience.您必须了解没有明确的答案,每个人都会根据他们的经验给您不同的建议/建议。

Generally, the preferred solution is to use a DTO approach, but how you implement that is left as an exercise for the developer.通常,首选的解决方案是使用 DTO 方法,但如何实现该方法留给开发人员练习。 Some developers are too lazy or simply accept/cope with the possible negative effects of using entity queries.一些开发人员太懒了,或者只是接受/应对使用实体查询可能产生的负面影响。 It really depends on your use case and your needs.这实际上取决于您的用例和您的需求。

I think though, that what you are looking for is a solution likeBlaze-Persistence Entity Views .不过,我认为,您正在寻找的是像Blaze-Persistence Entity Views这样的解决方案。

I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids.我创建了该库,以允许在 JPA 模型和自定义接口或抽象 class 定义的模型之间轻松映射,例如 Spring Data Projections on steroids。 The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.这个想法是您以您喜欢的方式定义您的目标结构(域模型),并通过 JPQL 表达式将 map 属性(吸气剂)定义为实体 model。

A DTO model for an example use case could look like the following with Blaze-Persistence Entity-Views:示例用例的 DTO model 使用 Blaze-Persistence Entity-Views 可能如下所示:

@EntityView(User.class)
public interface UserDto {
    @IdMapping
    Long getId();
    String getName();
    Set<RoleDto> getRoles();

    @EntityView(Role.class)
    interface RoleDto {
        @IdMapping
        Long getId();
        String getName();
    }
}

Querying is a matter of applying the entity view to a query, the simplest being just a query by id.查询是将实体视图应用于查询的问题,最简单的就是通过 id 进行查询。

UserDto a = entityViewManager.find(entityManager, UserDto.class, id);

The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features Spring 数据集成允许您几乎像 Spring 数据投影一样使用它: https://persistence.blazebit.com/documentation/entity-view/manual-html/。

Page<UserDto> findAll(Pageable pageable);

The best part is, it will only fetch the state that is actually necessary最好的部分是,它只会获取实际需要的 state

I've seen many people doing LAZY fetching for associations, that avoids big joins if you don't need data from other tables, and usually solves the problem.我见过很多人为关联做 LAZY fetching,如果你不需要来自其他表的数据,这可以避免大连接,并且通常可以解决问题。 However, the fetch strategy cannot be overridden per query, so you cannot choose to do LAZY fetching for some queries and then do EAGER fetching for others.但是,每个查询都不能覆盖 fetch 策略,因此您不能选择对某些查询执行 LAZY fetching,然后为其他查询执行 EAGER fetching。

DTO projections are indeed a better alternative. DTO 预测确实是一个更好的选择。 In pure JPA that requires messing with CriteriaBuilder.construct(....) , but Spring JPA has a very nice wrapper for it: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections In pure JPA that requires messing with CriteriaBuilder.construct(....) , but Spring JPA has a very nice wrapper for it: https://docs.spring.io/spring-data/jpa/docs/current/reference/ html/#projections

With DTO projections only the columns and joins you need will be included in the query.使用 DTO 投影,查询中只会包含您需要的列和连接。

For very large read-only operations, like reporting usecases, it's better to not use ORM frameworks, but use some specialized data frameworks.对于非常大的只读操作,比如报告用例,最好不要使用 ORM 框架,而是使用一些专门的数据框架。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM