HHH-10971 - Document flush operation order
This commit is contained in:
parent
1b83be8a75
commit
a27a13313d
|
@ -235,3 +235,49 @@ The `INSERT` statement was not executed because the persistence context because
|
||||||
====
|
====
|
||||||
This mode is useful when using multi-request logical transactions and only the last request should flush the persistence context.
|
This mode is useful when using multi-request logical transactions and only the last request should flush the persistence context.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
[[flushing-order]]
|
||||||
|
=== Flush operation order
|
||||||
|
|
||||||
|
From a database perspective, a row state can be altered using either an `INSERT`, an `UPDATE` or a `DELETE` statement.
|
||||||
|
Because https://vladmihalcea.com/2014/07/30/a-beginners-guide-to-jpahibernate-entity-state-transitions/[entity state changes] are automatically converted to SQL statements, it's important to know which entity actions are associated to a given SQL statement.
|
||||||
|
|
||||||
|
`INSERT`:: The `INSERT` statement is generated either by the `EntityInsertAction` or `EntityIdentityInsertAction`. These actions are scheduled by the `persist` operation, either explicitly or through cascading the `PersistEvent` from a parent to a child entity.
|
||||||
|
`DELETE`:: The `DELETE` statement is generated by the `EntityDeleteAction` or `OrphanRemovalAction`.
|
||||||
|
`UPDATE`:: The `UPDATE` statement is generated by `EntityUpdateAction` during flushing if the managed entity has been marked modified. The https://vladmihalcea.com/2014/08/21/the-anatomy-of-hibernate-dirty-checking/[dirty checking mechanism] is responsible for determining if a managed entity has been modified since it was first loaded.
|
||||||
|
|
||||||
|
Hibernate does not execute the SQL statements in the order of their associated entity state operations.
|
||||||
|
|
||||||
|
To visualize how this works, consider the following example:
|
||||||
|
|
||||||
|
[[flushing-order-example]]
|
||||||
|
.Flush operation order
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{sourcedir}/FlushOrderTest.java[tags=flushing-order-example]
|
||||||
|
----
|
||||||
|
|
||||||
|
[source, SQL, indent=0]
|
||||||
|
----
|
||||||
|
include::{extrasdir}/flushing-order-example.sql[]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
Even if we removed the first entity and then persist a new one, Hibernate is going to execute the `DELETE` statement after the `INSERT`.
|
||||||
|
|
||||||
|
[TIP]
|
||||||
|
====
|
||||||
|
The order in which SQL statements are executed is given by the `ActionQueue` and not by the order in which entity state operations have been previously defined.
|
||||||
|
====
|
||||||
|
|
||||||
|
The `ActionQueue` executes all operations in the following order:
|
||||||
|
|
||||||
|
. `OrphanRemovalAction`
|
||||||
|
. `EntityInsertAction` or `EntityIdentityInsertAction`
|
||||||
|
. `EntityUpdateAction`
|
||||||
|
. `CollectionRemoveAction`
|
||||||
|
. `CollectionUpdateAction`
|
||||||
|
. `CollectionRecreateAction`
|
||||||
|
. `EntityDeleteAction`
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
INSERT INTO Person (name, id)
|
||||||
|
VALUES ('John Doe', 2L)
|
||||||
|
|
||||||
|
DELETE FROM Person WHERE id = 1
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.userguide.flush;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
public class FlushOrderTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger( FlushOrderTest.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[]{
|
||||||
|
Person.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOrder() {
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
entityManager.createNativeQuery("delete from Person").executeUpdate();
|
||||||
|
});
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
Person person = new Person("John Doe");
|
||||||
|
person.id = 1L;
|
||||||
|
entityManager.persist(person);
|
||||||
|
});
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
log.info("testFlushSQL");
|
||||||
|
//tag::flushing-order-example[]
|
||||||
|
Person person = entityManager.find( Person.class, 1L);
|
||||||
|
entityManager.remove(person);
|
||||||
|
|
||||||
|
Person newPerson = new Person( );
|
||||||
|
newPerson.setId( 2L );
|
||||||
|
newPerson.setName( "John Doe" );
|
||||||
|
entityManager.persist( newPerson );
|
||||||
|
//end::flushing-order-example[]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Person")
|
||||||
|
public static class Person {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Person() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Person(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue