From 4960da8471021de26f96ece7d9d462308eaffe3a Mon Sep 17 00:00:00 2001 From: Vlad Mihalcea Date: Tue, 15 Nov 2016 18:41:35 +0200 Subject: [PATCH] HHH-11186 - Add examples for all Hibernate annotations Document more annotations: - @DynamicInsert - @DynamicUpdate - OptimisticLockType - @SelectBeforeUpdate --- .../userguide/appendices/Annotations.adoc | 10 +- .../userguide/chapters/domain/entity.adoc | 143 +++++++++++++++--- ...ptimistic-lock-type-all-update-example.sql | 17 +++ ...imistic-lock-type-dirty-update-example.sql | 11 ++ .../locking/OptimisticLockTypeAllTest.java | 122 +++++++++++++++ .../locking/OptimisticLockTypeDirtyTest.java | 124 +++++++++++++++ 6 files changed, 402 insertions(+), 25 deletions(-) create mode 100644 documentation/src/main/asciidoc/userguide/chapters/domain/extras/locking/locking-optimistic-lock-type-all-update-example.sql create mode 100644 documentation/src/main/asciidoc/userguide/chapters/domain/extras/locking/locking-optimistic-lock-type-dirty-update-example.sql create mode 100644 documentation/src/test/java/org/hibernate/userguide/locking/OptimisticLockTypeAllTest.java create mode 100644 documentation/src/test/java/org/hibernate/userguide/locking/OptimisticLockTypeDirtyTest.java diff --git a/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc index 6c64acf3de..1ffdf99a6b 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc @@ -722,6 +722,8 @@ The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibern By default, Hibernate uses a cached `INSERT` statement that sets all table columns. When the entity is annotated with the `@DynamicInsert` annotation, the `PreparedStatement` is going to include only the non-null columns. +See the <> section for more info on how `@DynamicInsert` works. + [[annotations-hibernate-dynamicupdate]] ==== `@DynamicUpdate` @@ -730,6 +732,8 @@ 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 <> section for more info on how `@DynamicUpdate` works. + [NOTE] ==== For reattachment of detached entities, the dynamic update is not possible without having the <> annotation as well. @@ -1010,8 +1014,8 @@ NONE:: The implicit optimistic locking mechanism is disabled. VERSION:: The implicit optimistic locking mechanism is using a dedicated version column. ALL:: The implicit optimistic locking mechanism is using *all* attributes as part of an expanded WHERE clause restriction for the `UPDATE` and `DELETE` SQL statements. DIRTY:: The implicit optimistic locking mechanism is using the *dirty* attributes (the attributes that were modified) as part of an expanded WHERE clause restriction for the `UPDATE` and `DELETE` SQL statements. -+ -When using `DIRTY`, you should also add the <> annotation and also <> so that detached entities are properly handled as well. + +See the <> section for more info. [[annotations-hibernate-orderby]] ==== `@OrderBy` @@ -1075,6 +1079,8 @@ According to Oracle documentation, `ROWID` is the fastest way to access a single The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/SelectBeforeUpdate.html[`@SelectBeforeUpdate`] annotation is used to specify that the current annotated entity state be selected from the database when determining whether to perform an update when the detached entity is reattached. +See the <> section for more info on how `@SelectBeforeUpdate` works. + [[annotations-hibernate-sort]] ==== [line-through]#`@Sort`# diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc index 1abe3362af..03052ffcde 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc @@ -1,6 +1,7 @@ [[entity]] === Entity types -:sourcedir: extras +:sourcedir: ../../../../../test/java/org/hibernate/userguide/locking +:extrasdir: extras .Usage of the word _entity_ [NOTE] @@ -99,7 +100,7 @@ The placement of the `@Id` annotation marks the <. + */ +package org.hibernate.userguide.locking; + +import java.sql.Timestamp; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.annotations.DynamicUpdate; +import org.hibernate.annotations.OptimisticLockType; +import org.hibernate.annotations.OptimisticLocking; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import org.jboss.logging.Logger; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; + +/** + * @author Vlad Mihalcea + */ +public class OptimisticLockTypeAllTest extends BaseEntityManagerFunctionalTestCase { + + private static final Logger log = Logger.getLogger( OptimisticLockTypeAllTest.class ); + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Person.class, + }; + } + + @Test + public void test() { + doInJPA( this::entityManagerFactory, entityManager -> { + Person person = new Person( ); + person.setId( 1L ); + person.setName( "John Doe" ); + person.setCountry( "US" ); + person.setCity( "New York" ); + person.setCreatedOn( new Timestamp( System.currentTimeMillis() ) ); + entityManager.persist( person ); + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::locking-optimistic-lock-type-all-update-example[] + Person person = entityManager.find( Person.class, 1L ); + person.setCity( "Washington D.C." ); + //end::locking-optimistic-lock-type-all-update-example[] + } ); + } + + //tag::locking-optimistic-lock-type-all-example[] + @Entity(name = "Person") + @OptimisticLocking(type = OptimisticLockType.ALL) + @DynamicUpdate + public static class Person { + + @Id + private Long id; + + @Column(name = "`name`") + private String name; + + private String country; + + private String city; + + @Column(name = "created_on") + private Timestamp createdOn; + + //Getters and setters are omitted for brevity + //end::locking-optimistic-lock-type-all-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 getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public Timestamp getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(Timestamp createdOn) { + this.createdOn = createdOn; + } + //tag::locking-optimistic-lock-type-all-example[] + } + //end::locking-optimistic-lock-type-all-example[] +} diff --git a/documentation/src/test/java/org/hibernate/userguide/locking/OptimisticLockTypeDirtyTest.java b/documentation/src/test/java/org/hibernate/userguide/locking/OptimisticLockTypeDirtyTest.java new file mode 100644 index 0000000000..917f1e3cba --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/locking/OptimisticLockTypeDirtyTest.java @@ -0,0 +1,124 @@ +/* + * 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 . + */ +package org.hibernate.userguide.locking; + +import java.sql.Timestamp; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.annotations.DynamicUpdate; +import org.hibernate.annotations.OptimisticLockType; +import org.hibernate.annotations.OptimisticLocking; +import org.hibernate.annotations.SelectBeforeUpdate; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import org.jboss.logging.Logger; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; + +/** + * @author Vlad Mihalcea + */ +public class OptimisticLockTypeDirtyTest extends BaseEntityManagerFunctionalTestCase { + + private static final Logger log = Logger.getLogger( OptimisticLockTypeDirtyTest.class ); + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Person.class, + }; + } + + @Test + public void test() { + doInJPA( this::entityManagerFactory, entityManager -> { + Person person = new Person( ); + person.setId( 1L ); + person.setName( "John Doe" ); + person.setCountry( "US" ); + person.setCity( "New York" ); + person.setCreatedOn( new Timestamp( System.currentTimeMillis() ) ); + entityManager.persist( person ); + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::locking-optimistic-lock-type-dirty-update-example[] + Person person = entityManager.find( Person.class, 1L ); + person.setCity( "Washington D.C." ); + //end::locking-optimistic-lock-type-dirty-update-example[] + } ); + } + + //tag::locking-optimistic-lock-type-dirty-example[] + @Entity(name = "Person") + @OptimisticLocking(type = OptimisticLockType.DIRTY) + @DynamicUpdate + @SelectBeforeUpdate + public static class Person { + + @Id + private Long id; + + @Column(name = "`name`") + private String name; + + private String country; + + private String city; + + @Column(name = "created_on") + private Timestamp createdOn; + + //Getters and setters are omitted for brevity + //end::locking-optimistic-lock-type-dirty-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 getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public Timestamp getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(Timestamp createdOn) { + this.createdOn = createdOn; + } + //tag::locking-optimistic-lock-type-dirty-example[] + } + //end::locking-optimistic-lock-type-dirty-example[] +}