为什么接口投影比带有Hibernate的Spring Data JPA中的构造函数投影和实体投影慢得多? [英] Why are interface projections much slower than constructor projections and entity projections in Spring Data JPA with Hibernate?

查看:104
本文介绍了为什么接口投影比带有Hibernate的Spring Data JPA中的构造函数投影和实体投影慢得多?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直想知道应该使用哪种类型的投影,所以我做了一点测试,涵盖了5种类型的投影(基于docs:

I've been wondering which kind of projections should I use, so I did a little test, which covered 5 types of projections (based on docs: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections):

1.实体投影

这只是Spring Data存储库提供的标准findAll().这里没什么好看的.

This is just a standard findAll() provided by Spring Data repository. Nothing fancy here.

服务:

List<SampleEntity> projections = sampleRepository.findAll();

实体:

@Entity
@Table(name = "SAMPLE_ENTITIES")
public class SampleEntity {
    @Id
    private Long id;
    private String name;
    private String city;
    private Integer age;
}

2.构造函数投影

服务:

List<NameOnlyDTO> projections = sampleRepository.findAllNameOnlyConstructorProjection();

存储库:

@Query("select new path.to.dto.NameOnlyDTO(e.name) from SampleEntity e")
List<NameOnlyDTO> findAllNameOnlyConstructorProjection();

数据传输对象:

@NoArgsConstructor
@AllArgsConstructor
public class NameOnlyDTO {
    private String name;
}

3.界面投影

服务:

List<NameOnly> projections = sampleRepository.findAllNameOnlyBy();

存储库:

List<NameOnly> findAllNameOnlyBy();

接口:

public interface NameOnly {
    String getName();
}

4.元组投影

服务:

List<Tuple> projections = sampleRepository.findAllNameOnlyTupleProjection();

存储库:

@Query("select e.name as name from SampleEntity e")
List<Tuple> findAllNameOnlyTupleProjection();

5.动态投影

服务:

List<DynamicProjectionDTO> projections = sampleRepository.findAllBy(DynamicProjectionDTO.class);

存储库:

<T> List<T> findAllBy(Class<T> type);

数据传输对象:

public class DynamicProjectionDTO {

    private String name;

    public DynamicProjectionDTO(String name) {
        this.name = name;
    }
}


一些其他信息:

该项目是使用gradle spring boot插件(版本2.0.4)构建的,该插件在后台使用了Spring 5.0.8.数据库:H2在内存中.

The project was built using gradle spring boot plugin (version 2.0.4), which uses Spring 5.0.8 under the hood. Database: H2 in memory.

结果:

Entity projections took 161.61 ms on average out of 100 iterations.
Constructor projections took 24.84 ms on average out of 100 iterations.
Interface projections took 252.26 ms on average out of 100 iterations.
Tuple projections took 21.41 ms on average out of 100 iterations.
Dynamic projections took 23.62 ms on average out of 100 iterations.
-----------------------------------------------------------------------
One iteration retrieved (from DB) and projected 100 000 objects.
-----------------------------------------------------------------------

注释:

可以理解,检索实体需要一些时间. Hibernate跟踪这些对象的更改,延迟加载等.

It is understandable that retrieving entities takes some time. Hibernate tracks these objects for changes, lazy loading and so on.

构造函数投影的速度非常快,并且在DTO方面没有任何限制,但是需要在@Query批注中手动创建对象.

Constructor projections are really fast and have no limitations on the DTO side, but require manual object creation in @Query annotation.

事实证明接口投影确实很慢.看到问题.

Interface projections turned out to be really slow. See question.

元组投影是最快的,但并不是最方便使用的.他们需要在JPQL中使用别名,并且必须通过调用.get("name")而不是.getName()来检索数据.

Tuple projections were the fastest, but are not the most convinient to play with. They need an alias in JPQL and the data has to be retrieved by calling .get("name") instead of .getName().

动态投影看起来很酷而且很快速,但是必须只有一个构造函数.不多不少.否则,Spring Data会引发异常,因为它不知道要使用哪一个(它需要使用构造函数参数来确定要从DB中检索哪些数据).

Dynamic projections look pretty cool and fast, but must have exactly one constructor. No more, no less. Otherwise Spring Data throws an exception, because it doesn't know which one to use (it takes constructor parameters to determine which data to retrieve from DB).

问题:

为什么接口投影要比检索实体花费更长的时间?返回的每个接口投影实际上都是一个代理.创建该代理是如此昂贵吗?如果是这样,它是否违反了预测的主要目的(因为它们本应比实体要快)?其他的预测看起来很棒.我真的很想对此有所了解.谢谢.

Why interface projections take longer than retrieving entities? Each interface projection returned is actually a proxy. Is it so expensive to create that proxy? If so, doesn't it defeat the main purpose of projections (since they are meant to be faster than entities)? Other projections look awesome tho. I would really love some insight on this. Thank you.

这是测试存储库: https://github.com/aurora-software -ks/spring-boot-projections-test ,以防您自己运行.设置非常容易.自述文件包含您需要了解的所有内容.

EDIT : Here is the test repository: https://github.com/aurora-software-ks/spring-boot-projections-test in case you want to run it yourself. It is very easy to set up. Readme contains everything you need to know.

推荐答案

我在较旧版本的Spring Data中遇到了类似的行为,这就是我的看法:

I experienced similar behavior with an older version of Spring Data and this was my take on it: https://blog.arnoldgalovics.com/how-much-projections-can-help/

我与Spring Data负责人Oliver Gierke进行了一次交谈,他进行了一些改进(这就是为什么您获得如此好"结果的原因:-)),但是从根本上来说,抽象与手动编码总是有代价的.

I had a talk with Oliver Gierke (Spring Data lead) and he made some improvements (that's why you get so "good" results :-) ) but basically there will be always a cost on having abstractions vs coding it manually.

这是其他一切之间的权衡.一方面,您具有灵活性,更轻松的开发,更少的维护(希望如此),另一方面,您可以完全控制,查询模型也更丑陋.

This is a trade-off as everything else is. On one hand you got flexibility, easier development, less maintenance (hopefully), on the other hand you get full control, a bit uglier query model.

这篇关于为什么接口投影比带有Hibernate的Spring Data JPA中的构造函数投影和实体投影慢得多?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆