From aeac516eeb2289c58cf70bba13b1600cd8db3b9f Mon Sep 17 00:00:00 2001 From: vladmihalcea Date: Wed, 27 Jan 2016 13:06:14 +0200 Subject: [PATCH] Migrate User Guide Locking chapter extras to test folder and old xml mapping to the Legacy appendix --- .../userguide/Hibernate_User_Guide.adoc | 1 + .../appendices/Legacy_DomainModel.adoc | 49 ++++++ .../extras/timestamp_version.xml | 0 .../extras/version_property.xml | 0 .../userguide/chapters/locking/Locking.adoc | 64 ++------ .../locking/extras/timestamp_version.java | 8 - .../locking/extras/updating_version.java | 11 -- .../locking/extras/version_annotation.java | 9 -- .../userguide/flush/AlwaysFlushTest.java | 2 - .../userguide/flush/AutoFlushTest.java | 2 - .../userguide/flush/CommitFlushTest.java | 2 - .../userguide/flush/ManualFlushTest.java | 2 - .../locking/ExplicitLockingTest.java | 2 - .../locking/OptimisticLockingTest.java | 146 ++++++++++++++++++ .../org/hibernate/userguide/ql/BulkTest.java | 2 - 15 files changed, 206 insertions(+), 94 deletions(-) create mode 100644 documentation/src/main/asciidoc/userguide/appendices/Legacy_DomainModel.adoc rename documentation/src/main/asciidoc/userguide/{chapters/locking => appendices}/extras/timestamp_version.xml (100%) rename documentation/src/main/asciidoc/userguide/{chapters/locking => appendices}/extras/version_property.xml (100%) delete mode 100644 documentation/src/main/asciidoc/userguide/chapters/locking/extras/timestamp_version.java delete mode 100644 documentation/src/main/asciidoc/userguide/chapters/locking/extras/updating_version.java delete mode 100644 documentation/src/main/asciidoc/userguide/chapters/locking/extras/version_annotation.java create mode 100644 documentation/src/test/java/org/hibernate/userguide/locking/OptimisticLockingTest.java diff --git a/documentation/src/main/asciidoc/userguide/Hibernate_User_Guide.adoc b/documentation/src/main/asciidoc/userguide/Hibernate_User_Guide.adoc index 903c2e24a2..ea2f65199e 100644 --- a/documentation/src/main/asciidoc/userguide/Hibernate_User_Guide.adoc +++ b/documentation/src/main/asciidoc/userguide/Hibernate_User_Guide.adoc @@ -28,6 +28,7 @@ include::chapters/envers/Envers.adoc[] include::chapters/portability/Portability.adoc[] include::appendices/Legacy_Bootstrap.adoc[] +include::appendices/Legacy_DomainModel.adoc[] include::appendices/Legacy_Criteria.adoc[] include::Bibliography.adoc[] diff --git a/documentation/src/main/asciidoc/userguide/appendices/Legacy_DomainModel.adoc b/documentation/src/main/asciidoc/userguide/appendices/Legacy_DomainModel.adoc new file mode 100644 index 0000000000..f7063498f2 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/appendices/Legacy_DomainModel.adoc @@ -0,0 +1,49 @@ +[[appendix-legacy-domain-model]] +== Legacy Domain Model +:sourcedir: extras + +.Declaring a version property in `hbm.xml` +==== +[source,xml] +---- +include::{sourcedir}/version_property.xml[] +---- +==== + +[cols=",",] +|======================================================================= +|column |The name of the column holding the version number. Optional, defaults to the property name. +|name |The name of a property of the persistent class. +|type |The type of the version number. Optional, defaults to `integer`. +|access |Hibernate's strategy for accessing the property value. Optional, defaults to `property`. +|unsaved-value |Indicates that an instance is newly instantiated and thus unsaved. +This distinguishes it from detached instances that were saved or loaded in a previous session. +The default value, `undefined`, indicates that the identifier property value should be used. Optional. +|generated |Indicates that the version property value is generated by the database. Optional, defaults to `never`. +|insert |Whether or not to include the `version` column in SQL `insert` statements. +Defaults to `true`, but you can set it to `false` if the database column is defined with a default value of `0`. +|======================================================================= + +.The timestamp element in `hbm.xml` +==== +[source,xml] +---- +include::{sourcedir}/timestamp_version.xml[] +---- +==== + +[cols=",",] +|======================================================================= +|column |The name of the column which holds the timestamp. Optional, defaults to the property name +|name |The name of a JavaBeans style property of Java type `Date` or `Timestamp` of the persistent class. +|access |The strategy Hibernate uses to access the property value. Optional, defaults to `property`. +|unsaved-value |A version property which indicates than instance is newly instantiated, and unsaved. +This distinguishes it from detached instances that were saved or loaded in a previous session. +The default value of `undefined` indicates that Hibernate uses the identifier property value. +|source |Whether Hibernate retrieves the timestamp from the database or the current JVM. +Database-based timestamps incur an overhead because Hibernate needs to query the database each time to determine the incremental next value. +However, database-derived timestamps are safer to use in a clustered environment. +Not all database dialects are known to support the retrieval of the database's current timestamp. +Others may also be unsafe for locking, because of lack of precision. +|generated |Whether the timestamp property value is generated by the database. Optional, defaults to `never`. +|======================================================================= \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/locking/extras/timestamp_version.xml b/documentation/src/main/asciidoc/userguide/appendices/extras/timestamp_version.xml similarity index 100% rename from documentation/src/main/asciidoc/userguide/chapters/locking/extras/timestamp_version.xml rename to documentation/src/main/asciidoc/userguide/appendices/extras/timestamp_version.xml diff --git a/documentation/src/main/asciidoc/userguide/chapters/locking/extras/version_property.xml b/documentation/src/main/asciidoc/userguide/appendices/extras/version_property.xml similarity index 100% rename from documentation/src/main/asciidoc/userguide/chapters/locking/extras/version_property.xml rename to documentation/src/main/asciidoc/userguide/appendices/extras/version_property.xml diff --git a/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc b/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc index 6168355dad..9c7fbcb0fe 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc @@ -1,6 +1,6 @@ [[locking]] == Locking -:sourcedir: extras +:sourcedir: ../../../../../test/java/org/hibernate/userguide/locking :extrasdir: extras In a relational database, locking refers to actions taken to prevent data from changing between the time it is read and the time is used. @@ -40,15 +40,16 @@ especially useful if you use assigned identifiers or composite keys. The version number mechanism for optimistic locking is provided through a `@Version` annotation. +[[locking-optimistic-version-number-example]] .@Version annotation ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/version_annotation.java[] +include::{sourcedir}/OptimisticLockingTest.java[tags=locking-optimistic-version-number-example] ---- ==== -Here, the version property is mapped to the `OPTLOCK` column, and the entity manager uses it to detect conflicting updates, +Here, the version property is mapped to the `version` column, and the entity manager uses it to detect conflicting updates, and prevent the loss of updates that would otherwise be overwritten by a last-commit-wins strategy. The version column can be any kind of type, as long as you define and implement the appropriate `UserVersionType`. @@ -62,39 +63,18 @@ To artificially increase the version number, see the documentation for propertie If the version number is generated by the database, such as a trigger, use the annotation `@org.hibernate.annotations.Generated(GenerationTime.ALWAYS)` on the version attribute. ==== -.Declaring a version property in `hbm.xml` -==== -[source,xml] ----- -include::{sourcedir}/version_property.xml[] ----- -==== - -[cols=",",] -|======================================================================= -|column |The name of the column holding the version number. Optional, defaults to the property name. -|name |The name of a property of the persistent class. -|type |The type of the version number. Optional, defaults to `integer`. -|access |Hibernate's strategy for accessing the property value. Optional, defaults to `property`. -|unsaved-value |Indicates that an instance is newly instantiated and thus unsaved. -This distinguishes it from detached instances that were saved or loaded in a previous session. -The default value, `undefined`, indicates that the identifier property value should be used. Optional. -|generated |Indicates that the version property value is generated by the database. Optional, defaults to `never`. -|insert |Whether or not to include the `version` column in SQL `insert` statements. -Defaults to `true`, but you can set it to `false` if the database column is defined with a default value of `0`. -|======================================================================= - [[locking-optimistic-timestamp]] === Timestamp Timestamps are a less reliable way of optimistic locking than version numbers, but can be used by applications for other purposes as well. Timestamping is automatically used if you the `@Version` annotation on a `Date` or `Calendar` property type. +[[locking-optimistic-version-timestamp-example]] .Using timestamps for optimistic locking ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/timestamp_version.java[] +include::{sourcedir}/OptimisticLockingTest.java[tags=locking-optimistic-version-timestamp-example] ---- ==== @@ -104,30 +84,6 @@ The default behavior is to use the database, and is also used if you don't speci The timestamp can also be generated by the database instead of Hibernate, if you use the `@org.hibernate.annotations.Generated(GenerationTime.ALWAYS)` annotation. -.The timestamp element in `hbm.xml` -==== -[source,xml] ----- -include::{sourcedir}/timestamp_version.xml[] ----- -==== - -[cols=",",] -|======================================================================= -|column |The name of the column which holds the timestamp. Optional, defaults to the property name -|name |The name of a JavaBeans style property of Java type `Date` or `Timestamp` of the persistent class. -|access |The strategy Hibernate uses to access the property value. Optional, defaults to `property`. -|unsaved-value |A version property which indicates than instance is newly instantiated, and unsaved. -This distinguishes it from detached instances that were saved or loaded in a previous session. -The default value of `undefined` indicates that Hibernate uses the identifier property value. -|source |Whether Hibernate retrieves the timestamp from the database or the current JVM. -Database-based timestamps incur an overhead because Hibernate needs to query the database each time to determine the incremental next value. -However, database-derived timestamps are safer to use in a clustered environment. -Not all database dialects are known to support the retrieval of the database's current timestamp. -Others may also be unsafe for locking, because of lack of precision. -|generated |Whether the timestamp property value is generated by the database. Optional, defaults to `never`. -|======================================================================= - [[locking-pessimistic]] === Pessimistic @@ -185,7 +141,7 @@ The scope can either be `NORMAL` (default value) or `EXTENDED`. The `EXTENDED` s ==== [source, JAVA, indent=0] ---- -include::{sourcedir}/../../../../../../test/java/org/hibernate/userguide/locking/ExplicitLockingTest.java[tags=locking-jpa-query-hints-timeout-example] +include::{sourcedir}/ExplicitLockingTest.java[tags=locking-jpa-query-hints-timeout-example] ---- [source, SQL, indent=0] @@ -218,7 +174,7 @@ The following example shows how to obtain shared database lock without waiting f ==== [source, JAVA, indent=0] ---- -include::{sourcedir}/../../../../../../test/java/org/hibernate/userguide/locking/ExplicitLockingTest.java[tags=locking-buildLockRequest-example] +include::{sourcedir}/ExplicitLockingTest.java[tags=locking-buildLockRequest-example] ---- [source, SQL, indent=0] diff --git a/documentation/src/main/asciidoc/userguide/chapters/locking/extras/timestamp_version.java b/documentation/src/main/asciidoc/userguide/chapters/locking/extras/timestamp_version.java deleted file mode 100644 index 4c3f723db3..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/locking/extras/timestamp_version.java +++ /dev/null @@ -1,8 +0,0 @@ -@Entity -public class Flight implements Serializable { - - ... - - @Version - public Date getLastUpdate() {...} -} \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/locking/extras/updating_version.java b/documentation/src/main/asciidoc/userguide/chapters/locking/extras/updating_version.java deleted file mode 100644 index 3e3d109aff..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/locking/extras/updating_version.java +++ /dev/null @@ -1,11 +0,0 @@ -Session session = sessionFactory.openSession(); -Transaction tx = session.beginTransaction(); - -int updatedEntities = session.createQuery( - "update versioned Customer set name = :newName where name = :oldName" ) - .setString( "newName",newName ) - .setString( "oldName",oldName ) - .executeUpdate(); - -tx.commit(); -session.close(); diff --git a/documentation/src/main/asciidoc/userguide/chapters/locking/extras/version_annotation.java b/documentation/src/main/asciidoc/userguide/chapters/locking/extras/version_annotation.java deleted file mode 100644 index 5098d42e9a..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/locking/extras/version_annotation.java +++ /dev/null @@ -1,9 +0,0 @@ -@Entity -public class Flight implements Serializable { - - ... - - @Version - @Column( name = "OPTLOCK" ) - public Integer getVersion() {...} -} \ No newline at end of file diff --git a/documentation/src/test/java/org/hibernate/userguide/flush/AlwaysFlushTest.java b/documentation/src/test/java/org/hibernate/userguide/flush/AlwaysFlushTest.java index 2bff632ac8..660330416e 100644 --- a/documentation/src/test/java/org/hibernate/userguide/flush/AlwaysFlushTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/flush/AlwaysFlushTest.java @@ -27,8 +27,6 @@ import static org.hibernate.userguide.util.TransactionUtil.doInJPA; import static org.junit.Assert.assertTrue; /** - * AlwaysFlushTest - Always Flush Test - * * @author Vlad Mihalcea */ public class AlwaysFlushTest extends BaseEntityManagerFunctionalTestCase { diff --git a/documentation/src/test/java/org/hibernate/userguide/flush/AutoFlushTest.java b/documentation/src/test/java/org/hibernate/userguide/flush/AutoFlushTest.java index 9f0b77d43d..d4ae50bf9e 100644 --- a/documentation/src/test/java/org/hibernate/userguide/flush/AutoFlushTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/flush/AutoFlushTest.java @@ -23,8 +23,6 @@ import static org.hibernate.userguide.util.TransactionUtil.doInJPA; import static org.junit.Assert.assertTrue; /** - * AlwaysFlushTest - Always Flush Test - * * @author Vlad Mihalcea */ public class AutoFlushTest extends BaseEntityManagerFunctionalTestCase { diff --git a/documentation/src/test/java/org/hibernate/userguide/flush/CommitFlushTest.java b/documentation/src/test/java/org/hibernate/userguide/flush/CommitFlushTest.java index f0da27c168..7fa3ecf519 100644 --- a/documentation/src/test/java/org/hibernate/userguide/flush/CommitFlushTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/flush/CommitFlushTest.java @@ -27,8 +27,6 @@ import static org.junit.Assert.assertTrue; import static org.hibernate.userguide.util.TransactionUtil.doInJPA; /** - * CommitFlushTest - Commit Flush Test - * * @author Vlad Mihalcea */ public class CommitFlushTest extends BaseEntityManagerFunctionalTestCase { diff --git a/documentation/src/test/java/org/hibernate/userguide/flush/ManualFlushTest.java b/documentation/src/test/java/org/hibernate/userguide/flush/ManualFlushTest.java index 7971b7d633..143b3c2a03 100644 --- a/documentation/src/test/java/org/hibernate/userguide/flush/ManualFlushTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/flush/ManualFlushTest.java @@ -28,8 +28,6 @@ import static org.hibernate.userguide.util.TransactionUtil.doInJPA; import static org.junit.Assert.assertTrue; /** - * ManualFlushTest - Manual Flush Test - * * @author Vlad Mihalcea */ public class ManualFlushTest extends BaseEntityManagerFunctionalTestCase { diff --git a/documentation/src/test/java/org/hibernate/userguide/locking/ExplicitLockingTest.java b/documentation/src/test/java/org/hibernate/userguide/locking/ExplicitLockingTest.java index 62e7d1a1a6..28fc64745a 100644 --- a/documentation/src/test/java/org/hibernate/userguide/locking/ExplicitLockingTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/locking/ExplicitLockingTest.java @@ -27,8 +27,6 @@ import static org.hibernate.userguide.util.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; /** - * BuildLockRequestTest - Build Lock Request Test - * * @author Vlad Mihalcea */ public class ExplicitLockingTest extends BaseEntityManagerFunctionalTestCase { diff --git a/documentation/src/test/java/org/hibernate/userguide/locking/OptimisticLockingTest.java b/documentation/src/test/java/org/hibernate/userguide/locking/OptimisticLockingTest.java new file mode 100644 index 0000000000..a7092b80d0 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/locking/OptimisticLockingTest.java @@ -0,0 +1,146 @@ +package org.hibernate.userguide.locking; + +import java.util.Date; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Version; + +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 OptimisticLockingTest extends BaseEntityManagerFunctionalTestCase { + + private static final Logger log = Logger.getLogger( OptimisticLockingTest.class ); + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Person.class, + Phone.class + }; + } + + @Test + public void test() { + Phone _phone = doInJPA( this::entityManagerFactory, entityManager -> { + Person person = new Person( ); + person.setName( "John Doe" ); + entityManager.persist( person ); + + Phone phone = new Phone( ); + phone.setNumber( "123-456-7890" ); + phone.setPerson( person ); + entityManager.persist( phone ); + + return phone; + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + Person person = entityManager.find( Person.class, _phone.getPerson().getId() ); + person.setName( person.getName().toUpperCase() ); + + Phone phone = entityManager.find( Phone.class, _phone.getId() ); + phone.setNumber( phone.getNumber().replace( "-", " ") ); + } ); + } + + @Entity(name = "Person") + public static class Person { + + @Id + @GeneratedValue + private Long id; + + @Column(name = "`name`") + private String name; + + //tag::locking-optimistic-version-number-example[] + @Version + private long version; + //end::locking-optimistic-version-number-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 long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + } + + @Entity(name = "Phone") + public static class Phone { + + @Id + @GeneratedValue + private Long id; + + private String number; + + @ManyToOne + private Person person; + + //tag::locking-optimistic-version-timestamp-example[] + @Version + private Date version; + //end::locking-optimistic-version-timestamp-example[] + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + public Person getPerson() { + return person; + } + + public void setPerson(Person person) { + this.person = person; + } + + public Date getVersion() { + return version; + } + + public void setVersion(Date version) { + this.version = version; + } + } +} diff --git a/documentation/src/test/java/org/hibernate/userguide/ql/BulkTest.java b/documentation/src/test/java/org/hibernate/userguide/ql/BulkTest.java index 1a7b3e7b8a..7df107341a 100644 --- a/documentation/src/test/java/org/hibernate/userguide/ql/BulkTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/ql/BulkTest.java @@ -14,8 +14,6 @@ import static org.hibernate.userguide.util.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; /** - * BulkTest - Bulk JPQL Test - * * @author Vlad Mihalcea */ public class BulkTest extends BaseEntityManagerFunctionalTestCase {