【问题标题】:Spring Data JPA make many selects by id when saveSpring Data JPA 在保存时通过 id 进行许多选择
【发布时间】:2021-02-19 11:35:51
【问题描述】:

我有这个模型:

数据模型:

@Table(name = "data_model")
public class DataModel {

    @Id
    @GeneratedValue
    @Column(name = "model_id")
    private Integer id;

    @OneToMany(orphanRemoval = true, mappedBy = "dataModel", cascade = {CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.MERGE})
    private List<OutputField> outputFields;

    @OneToMany(orphanRemoval = true, mappedBy = "dataModel", cascade = {CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.MERGE})
    private List<IncrementField> incrementFields;

}

输出字段:

@Table(name = "data_model_output_field")
public class OutputField {

    @Id
    @GeneratedValue
    @Column(name = "output_field_id")
    private Integer id;

    @ManyToOne(optional = false, fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
    @JoinColumn(name = "model_id")
    private DataModel dataModel;

}

增量字段:

@Entity
@Table(name = "data_model_increment_field")
public class IncrementField {

    @Id
    @GeneratedValue
    @Column(name = "increment_field_id")
    private Integer id;
    
    @ManyToOne(optional = false, fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
    @JoinColumn(name = "model_id")
    private DataModel dataModel;
}

我有服务方法:

@Transactional
public void createOrUpdate(DataModel dataModel) {
    DataModel savedDataModel = dataModelRepository.save(dataModel);
}

当我尝试保存实体时,在日志中我看到许多选择查询:

Name:test-ds, Connection:9, Time:0, Success:True
Type:Prepared, Batch:False, QuerySize:1, BatchSize:0
Query:["
    select
        outputfiel0_.model_id as model_id8_4_0_
    from
        data_model_output_field outputfiel0_ 
    where
        outputfiel0_.output_field_id=1"]


Name:test-ds, Connection:9, Time:0, Success:True
Type:Prepared, Batch:False, QuerySize:1, BatchSize:0
Query:["
    select
        outputfiel0_.model_id as model_id8_4_0_
    from
        data_model_output_field outputfiel0_ 
    where
        outputfiel0_.output_field_id=2"]


Name:test-ds, Connection:9, Time:0, Success:True
Type:Prepared, Batch:False, QuerySize:1, BatchSize:0
Query:["
    select
        outputfiel0_.model_id as model_id8_4_0_
    from
        data_model_output_field outputfiel0_ 
    where
        outputfiel0_.output_field_id=3"]


Name:test-ds, Connection:9, Time:0, Success:True
Type:Prepared, Batch:False, QuerySize:1, BatchSize:0
Query:["
    select
        outputfiel0_.model_id as model_id8_4_0_
    from
        data_model_output_field outputfiel0_ 
    where
        outputfiel0_.output_field_id=4"]

Name:test-ds, Connection:9, Time:0, Success:True
Type:Prepared, Batch:False, QuerySize:1, BatchSize:0
Query:["
    select
        outputfiel0_.model_id as model_id8_4_0_
    from
        data_model_output_field outputfiel0_ 
    where
        outputfiel0_.model_id=2"]

它通过 id 获取每个字段。但是他为什么这样做,他可以立即通过model_id拿起名单?

此外,在日志的最后,他做到了。那他为什么需要之前的查询呢?

更新

重现的简单示例:https://github.com/eaxdev/simple-web-app

【问题讨论】:

    标签: java hibernate spring-data-jpa spring-data


    【解决方案1】:

    那是因为save 方法使用EntityManager.merge 刷新更改,而您正在使用 MERGE 级联。我不知道您要在此处保存哪种对象图,但似乎 outputFields 集合有 4 个条目首先经历 MERGE 级联,即 Hibernate 选择这些对象的当前状态,以便它可以刷新更改。接下来,Hibernate 尝试刷新 DataModel#outputFields 关系的更改,即外键,它需要查询所有对象,以便知道要删除什么(我认为这是由于孤立删除而需要的)。

    在我看来OutputFieldIncrementFieldDataModel 有组合关系,那么为什么不将它们建模为@Embeddable?这样,Hibernate 可以更有效地管理关联。

    【讨论】:

    • 您是否建议OutputFieldIncrementField 实体注释@Embeddable?我试图这样做,但没有任何效果。在问题中,我附上了一个链接到我的示例的 github
    • 如果您使用@Embeddable,您还必须使用@ElementCollection 而不是@OneToMany,并从OutputFieldIncrementField 类中删除ID。 “没有任何影响”是什么意思?
    • 我不太明白为什么要删除表中的主键?这些是完全不同的表,它们通过OneToMany 链接
    • 因为当您使用 @ElementCollection@Embeddable 时,PK 是不必要的/错误的。
    猜你喜欢
    • 2015-05-10
    • 2019-11-03
    • 2023-03-29
    • 2020-02-03
    • 2018-08-21
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 2019-09-30
    相关资源
    最近更新 更多