When inserting entities that have foreign key relationships to each other as part of a single flush, sometimes Hibernate does this in a single step, doing an INSERT SQL command for each entity that inserts the row with the foreign key reference already present, but sometimes it does it in two steps, first INSERTing the rows with some or all of the foreign key references null, and then going back an UPDATEing them to add in the (rest of the) foreign key relationships. I haven't located the code responsible for this decision or fully determined under what circumstances it does the INSERT-only approach and when it does the INSERT-then-UPDATE approach. However, my testing suggests that when all the foreign key relationships involved are unidirectional optional @OneToMany relationships (one parent, many children), then it always INSERTS all the rows with all foreign keys null, and then UPDATES the foreign key relationships into place. Making all the relationships bidirectional optional @OneToMany relationships seems to reduce but not eliminate the use of UPDATEs. In this situation (where all foreign keys between a particular pair of tables in the transaction will be filled in with UPDATEs), then ActionQueue.sort(List<AbstractEntityInsertAction> insertions) should be ignoring all the relationships (since if you're going to create them using an UPDATE, the order of the INSERTs doesn't matter – no constraint violations will occur regardless of the order of INSERTion, since all foreign keys are null during INSERTion). However, this isn't the case – the sort(...) code then still spends time needlessly sorting the INSERTions. So it seems clear that there are some foreign key relationships that the sort(...) code should be ignoring (any where Hibernate will always fill them in with an UPDATE after the INSERTs are done, so they don't constrain the order of INSERTions) but is not ignoring. So it's attempting to satisfy unnecessary ordering requirements, which is likely to make its sorting take longer than necessary (and could make it needlessly assume that there is a circular relationship that makes there be no viable INSERTion order).
I don't have a test case to submit for this: since it's basically just a performance issue (the sort code is doing unnecessary work to try to avoid a constraint violation that won't happen) I'm not sure how to create one. Even if we create a circular dependency using links some of which the sort(...) doesn't need to worry about, all it will currently do is sort for a long time, eventually give up, then the INSERTs and UPDATEs will work – so I don't see how to construct a failing test.
That can happen if you are using unidirectional associations.However, unidirectional associations don't perform very well even from an SQL perspective.
However, I'm interested in seeing a replicating test case for this statement:
Because I don't recall ever seeing that for @ManyToOne or bidirectional associations.
I believe this can be observed happening for bidirectional relationships by setting suitable breakpoints in the fuzz test that I submitted as a test case for (which uses bidirectional relationships).