HHH-11186 - Add examples for all Hibernate annotations
Document DynamicUpdate annotation
This commit is contained in:
parent
020414e1aa
commit
3ee36aa420
|
@ -734,7 +734,7 @@ The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibern
|
|||
By default, Hibernate uses a cached `UPDATE` statement that sets all table columns.
|
||||
When the entity is annotated with the `@DynamicUpdate` annotation, the `PreparedStatement` is going to include only the columns whose values have been changed.
|
||||
|
||||
See the <<chapters/domain/entity.adoc#locking-optimistic-lock-type-dirty-example, `OptimisticLockType.DIRTY` mapping>> section for more info on how `@DynamicUpdate` works.
|
||||
See the <<chapters/pc/PersistenceContext.adoc#pc-managed-state-dynamic-update,`@DynamicUpdate`>> section for more info.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
|
|
|
@ -251,6 +251,83 @@ include::{sourcedir}/PersistenceContextTest.java[tags=pc-managed-state-native-ex
|
|||
----
|
||||
====
|
||||
|
||||
By default, when you modify an entity, all columns but the identifier are being set during update.
|
||||
|
||||
Therefore, considering you have the following `Product` entity mapping:
|
||||
|
||||
[[pc-managed-state-update-mapping-example]]
|
||||
.`Product` entity mapping
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/NoDynamicUpdateTest.java[tags=pc-managed-state-update-mapping-example]
|
||||
----
|
||||
====
|
||||
|
||||
If you persist the following `Product` entity:
|
||||
|
||||
[[pc-managed-state-update-persist-example]]
|
||||
.Persisting a `Product` entity
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/NoDynamicUpdateTest.java[tags=pc-managed-state-update-persist-example]
|
||||
----
|
||||
====
|
||||
|
||||
When you modify the `Product` entity, Hibernate generates the following SQL UPDATE statement:
|
||||
|
||||
[[pc-managed-state-update-example]]
|
||||
.Modifying the `Product` entity
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/NoDynamicUpdateTest.java[tags=pc-managed-state-update-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/pc-managed-state-update-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
The default UPDATE statement containing all columns has two advantages:
|
||||
|
||||
- it allows you to better benefit from JDBC Statement caching.
|
||||
- it allows you to enable batch updates even if multiple entities modify different properties.
|
||||
|
||||
However, there is also one downside to including all columns in the SQL UPDATE statement.
|
||||
If you have multiple indexes, the database might update those redundantly even if you don't actually modify all column values.
|
||||
|
||||
To fix this issue, you can use dynamic updates.
|
||||
|
||||
[[pc-managed-state-dynamic-update]]
|
||||
==== Dynamic updates
|
||||
|
||||
To enable dynamic updates, you need to annotate the entity with the `@DynamicUpdate` annotation:
|
||||
|
||||
[[pc-managed-state-dynamic-update-mapping-example]]
|
||||
.`Product` entity mapping
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/DynamicUpdateTest.java[tags=pc-managed-state-dynamic-update-mapping-example]
|
||||
----
|
||||
====
|
||||
|
||||
This time, when reruning the previous test case, Hibernate generates the following SQL UPDATE statement:
|
||||
|
||||
[[pc-managed-state-dynamic-update-example]]
|
||||
.Modifying the `Product` entity with a dynamic update
|
||||
====
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/pc-managed-state-dynamic-update-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
The dynamic update allows you to set just the columns sthat were modified in the associated entity.
|
||||
|
||||
[[pc-refresh]]
|
||||
=== Refresh entity state
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
UPDATE
|
||||
Product
|
||||
SET
|
||||
price_cents = ?
|
||||
WHERE
|
||||
id = ?
|
||||
|
||||
-- binding parameter [1] as [INTEGER] - [2499]
|
||||
-- binding parameter [2] as [BIGINT] - [1]
|
|
@ -0,0 +1,15 @@
|
|||
UPDATE
|
||||
Product
|
||||
SET
|
||||
description = ?,
|
||||
name = ?,
|
||||
price_cents = ?,
|
||||
quantity = ?
|
||||
WHERE
|
||||
id = ?
|
||||
|
||||
-- binding parameter [1] as [VARCHAR] - [Get the most out of your persistence layer]
|
||||
-- binding parameter [2] as [VARCHAR] - [High-Performance Java Persistence]
|
||||
-- binding parameter [3] as [INTEGER] - [2499]
|
||||
-- binding parameter [4] as [INTEGER] - [10000]
|
||||
-- binding parameter [5] as [BIGINT] - [1]
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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.pc;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
import org.hibernate.annotations.Target;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.test.annotations.id.entities.Shoe;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class DynamicUpdateTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Product.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycle() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
|
||||
Product book = new Product();
|
||||
book.setId( 1L );
|
||||
book.setName( "High-Performance Java Persistence" );
|
||||
book.setDescription( "get the most out of your persistence layer" );
|
||||
book.setPriceCents( 29_99 );
|
||||
book.setQuantity( 10_000 );
|
||||
|
||||
entityManager.persist( book );
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
|
||||
Product book = entityManager.find( Product.class, 1L );
|
||||
book.setPriceCents( 24_99 );
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::pc-managed-state-dynamic-update-mapping-example[]
|
||||
@Entity(name = "Product")
|
||||
@DynamicUpdate
|
||||
public static class Product {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
private String description;
|
||||
|
||||
@Column(name = "price_cents")
|
||||
private Integer priceCents;
|
||||
|
||||
@Column
|
||||
private Integer quantity;
|
||||
|
||||
//Getters and setters are omitted for brevity
|
||||
|
||||
//end::pc-managed-state-dynamic-update-mapping-example[]
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Integer getPriceCents() {
|
||||
return priceCents;
|
||||
}
|
||||
|
||||
public void setPriceCents(Integer priceCents) {
|
||||
this.priceCents = priceCents;
|
||||
}
|
||||
|
||||
public Integer getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(Integer quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
//tag::pc-managed-state-dynamic-update-mapping-example[]
|
||||
}
|
||||
//end::pc-managed-state-dynamic-update-mapping-example[]
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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.pc;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class NoDynamicUpdateTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Product.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycle() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
|
||||
//tag::pc-managed-state-update-persist-example[]
|
||||
Product book = new Product();
|
||||
book.setId( 1L );
|
||||
book.setName( "High-Performance Java Persistence" );
|
||||
book.setDescription( "Get the most out of your persistence layer" );
|
||||
book.setPriceCents( 29_99 );
|
||||
book.setQuantity( 10_000 );
|
||||
|
||||
entityManager.persist( book );
|
||||
//end::pc-managed-state-update-persist-example[]
|
||||
} );
|
||||
|
||||
|
||||
//tag::pc-managed-state-update-example[]
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Product book = entityManager.find( Product.class, 1L );
|
||||
book.setPriceCents( 24_99 );
|
||||
} );
|
||||
//end::pc-managed-state-update-example[]
|
||||
}
|
||||
|
||||
//tag::pc-managed-state-update-mapping-example[]
|
||||
@Entity(name = "Product")
|
||||
public static class Product {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
private String description;
|
||||
|
||||
@Column(name = "price_cents")
|
||||
private Integer priceCents;
|
||||
|
||||
@Column
|
||||
private Integer quantity;
|
||||
|
||||
//Getters and setters are omitted for brevity
|
||||
|
||||
//end::pc-managed-state-update-mapping-example[]
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Integer getPriceCents() {
|
||||
return priceCents;
|
||||
}
|
||||
|
||||
public void setPriceCents(Integer priceCents) {
|
||||
this.priceCents = priceCents;
|
||||
}
|
||||
|
||||
public Integer getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(Integer quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
//tag::pc-managed-state-update-mapping-example[]
|
||||
}
|
||||
//end::pc-managed-state-update-mapping-example[]
|
||||
}
|
Loading…
Reference in New Issue