简体   繁体   中英

How to get rid of a N+1 query on Hibernate/JPA updating children rows with their parent ID

I'm troubleshooting some performance issues, and I've noticed that hibernate is generating N+1 queries for updating the parent id in a child entity.

I'm using Spring 4.3.4 , Hibernate 5.2.5 , and Spring Data 1.10.5

I have code like this:

Parent p = createParent();
Parent savedParent = parentRepo.save(p);
savedParent.addChild(new Child());
savedParent.addChild(new Child());
savedParent.addChild(new Child());
parentRepo.save(savedParent);

The issue is that it generates sql like this:

insert into parent (col1, col2, col3) values (1,2,3)
insert into child (col1, col2, col3, parent_id) values (1,2,3, PARENT_ID), (1,2,3, PARENT_ID), (1,2,3, PARENT_ID)
update child set parent_id = PARENT_ID where id = x
update child set parent_id = PARENT_ID where id = x+1
update child set parent_id = PARENT_ID where id = x+2

My mapping looks like this

Parent{
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "parent_id", nullable = false)
    @BatchSize(size = 500)
    private List<Child> items;
}

Child{
    @ManyToOne(optional = false)
    @JoinColumn(name = "parent_id", referencedColumnName = "id", nullable = false, insertable= false, updatable = false)
    private Parent parent;
}

I've tried messing around with saving the parent first to make sure it had an id before adding the children and just doing one massive save without saving the parent first, but it always generates a N+1 query. I've made sure that I set the inventory on the child in code just to make sure that it knows it's parent, but that also doesn't seemed to have helped. All of my googling around goes in to how to prevent most types of N+1 queries, but not this particular type. It's odd because it sets the parent id correctly in the insert, but then feels the need to update it, even though it didn't change.

Please try the below code in which I have added mappedBy attribute. This is case of simple bidirectional mapping which you are setting in object graph but not reflected by hibernate relationships.

Parent{
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true,mappedBy="parent")
@JoinColumn(name = "parent_id", nullable = false)
@BatchSize(size = 500)
private List<Child> items;
}

I got it working, I had to change my mappings to this:

Parent{
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "parent")
    @BatchSize(size = 500)
    private List<Child> items;
}

Child{
    @ManyToOne(optional = false)
    @JoinColumn(name = "parent_id", referencedColumnName = "id", nullable = false)
    private Parent parent;
}

Then everything worked

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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