diff --git a/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc index 7f8b548a5d..67681f6491 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc @@ -578,7 +578,7 @@ The http://docs.oracle.com/javaee/7/api/javax/persistence/UniqueConstraint.html[ The http://docs.oracle.com/javaee/7/api/javax/persistence/Version.html[`@Version`] annotation is used to specify the version attribute used for optimistic locking. -See the <> section for more info. +See the <> section for more info. [[annotations-hibernate]] === Hibernate annotations @@ -1068,7 +1068,7 @@ VERSION:: The implicit optimistic locking mechanism is using a dedicated version 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. -See the <> section for more info. +See the <> section for more info. [[annotations-hibernate-orderby]] ==== `@OrderBy` diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc index aa0dab72d8..e9c9e77da0 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc @@ -271,145 +271,6 @@ It's possible to use the entity identifier for equality check, but it needs a wo For details on mapping the identifier, see the <> chapter. -[[entity-pojo-optlock]] -==== Mapping optimistic locking - -JPA defines support for optimistic locking based on either a version (sequential numeric) or timestamp strategy. -To enable this style of optimistic locking simply add the `javax.persistence.Version` to the persistent attribute that defines the optimistic locking value. -According to JPA, the valid types for these attributes are limited to: - -* `int` or `Integer` -* `short` or `Short` -* `long` or `Long` -* `java.sql.Timestamp` - -[[entity-pojo-optlock-version-example]] -.`@Version` annotation mapping -==== -[source,java] ----- -include::{extrasdir}/entity/Version.java[] ----- - -[source,java] ----- -include::{extrasdir}/entity/Timestamp.java[] ----- - -[source,java] ----- -include::{extrasdir}/entity/Instant.java[] ----- -==== - -[[entity-pojo-optlock-versionless]] -===== Versionless optimistic locking - -Although the default `@Version` property optimistic locking mechanism is sufficient in many situations, -sometimes, you need rely on the actual database row column values to prevent *lost updates*. - -Hibernate supports a form of optimistic locking that does not require a dedicated "version attribute". -This is also useful for use with modeling legacy schemas. - -The idea is that you can get Hibernate to perform "version checks" using either all of the entity's attributes, or just the attributes that have changed. -This is achieved through the use of the -https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/OptimisticLocking.html[`@OptimisticLocking`] -annotation which defines a single attribute of type -https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/OptimisticLockType.html[`org.hibernate.annotations.OptimisticLockType`]. - -There are 4 available OptimisticLockTypes: - -`NONE`:: - optimistic locking is disabled even if there is a `@Version` annotation present -`VERSION` (the default):: - performs optimistic locking based on a `@Version` as described above -`ALL`:: - performs optimistic locking based on _all_ fields as part of an expanded WHERE clause restriction for the UPDATE/DELETE SQL statements -`DIRTY`:: - performs optimistic locking based on _dirty_ fields as part of an expanded WHERE clause restriction for the UPDATE/DELETE SQL statements - -[[entity-pojo-optlock-versionless-all]] -====== Versionless optimistic locking using `OptimisticLockType.ALL` - -[[locking-optimistic-lock-type-all-example]] -.`OptimisticLockType.ALL` mapping example -==== -[source,java] ----- -include::{sourcedir-locking}/OptimisticLockTypeAllTest.java[tag=locking-optimistic-lock-type-all-example,indent=0] ----- -==== - -When you need to modify the `Person` entity above: - -[[locking-optimistic-lock-type-all-update-example]] -.`OptimisticLockType.ALL` update example -==== -[source,java] ----- -include::{sourcedir-locking}/OptimisticLockTypeAllTest.java[tag=locking-optimistic-lock-type-all-update-example,indent=0] ----- - -[source,SQL] ----- -include::{extrasdir}/locking/locking-optimistic-lock-type-all-update-example.sql[] ----- -==== - -As you can see, all the columns of the associated database row are used in the `WHERE` clause. -If any column has changed after the row was loaded, there won't be any match, and a `StaleStateException` or an `OptimisticLockException` -is going to be thrown. - -[NOTE] -==== -When using `OptimisticLockType.ALL`, you should also use `@DynamicUpdate` because the `UPDATE` statement must take into consideration all the entity property values. -==== - -[[entity-pojo-optlock-versionless-dirty]] -====== Versionless optimistic locking using `OptimisticLockType.DIRTY` - -The `OptimisticLockType.DIRTY` differs from `OptimisticLockType.ALL` -in that it only takes into consideration the entity properties that have changed -since the entity was loaded in the currently running Persistence Context. - -[[locking-optimistic-lock-type-dirty-example]] -.`OptimisticLockType.DIRTY` mapping example -==== -[source,java] ----- -include::{sourcedir-locking}/OptimisticLockTypeDirtyTest.java[tag=locking-optimistic-lock-type-dirty-example,indent=0] ----- -==== - -When you need to modify the `Person` entity above: - -[[locking-optimistic-lock-type-dirty-update-example]] -.`OptimisticLockType.DIRTY` update example -==== -[source,java] ----- -include::{sourcedir-locking}/OptimisticLockTypeDirtyTest.java[tag=locking-optimistic-lock-type-dirty-update-example,indent=0] ----- - -[source,SQL] ----- -include::{extrasdir}/locking/locking-optimistic-lock-type-dirty-update-example.sql[] ----- -==== - -This time, only the database column that has changed was used in the `WHERE` clause. - -[NOTE] -==== -The main advantage of `OptimisticLockType.DIRTY` over `OptimisticLockType.ALL` -and the default `OptimisticLockType.VERSION` used implicitly along with the `@Version` mapping, -is that it allows you to minimize the risk of `OptimisticLockException` across non-overlapping entity property changes. - -When using `OptimisticLockType.DIRTY`, you should also use `@DynamicUpdate` because the `UPDATE` statement must take into consideration all the dirty entity property values, -and also the `@SelectBeforeUpdate` annotation so that detached entities are properly handled by the -https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/Session.html#update-java.lang.Object-[`Session#update(entity)`] operation. -==== - [[entity-sql-query-mapping]] ==== Mapping the entity to a SQL query diff --git a/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc b/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc index a999a6631c..e17036e0f8 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc @@ -18,6 +18,7 @@ and requires resources to be locked after they are read and only unlocked after Hibernate provides mechanisms for implementing both types of locking in your applications. +[[locking-optimistic]] === Optimistic When your application uses long transactions or conversations that span several database transactions, @@ -35,8 +36,39 @@ Declaring a nullable version or timestamp property is an easy way to avoid probl especially useful if you use assigned identifiers or composite keys. ==== +[[locking-optimistic-mapping]] +==== Mapping optimistic locking + +JPA defines support for optimistic locking based on either a version (sequential numeric) or timestamp strategy. +To enable this style of optimistic locking simply add the `javax.persistence.Version` to the persistent attribute that defines the optimistic locking value. +According to JPA, the valid types for these attributes are limited to: + +* `int` or `Integer` +* `short` or `Short` +* `long` or `Long` +* `java.sql.Timestamp` + +[[locking-optimistic-version-example]] +.`@Version` annotation mapping +==== +[source,java] +---- +include::{extrasdir}/entity/Version.java[] +---- + +[source,java] +---- +include::{extrasdir}/entity/Timestamp.java[] +---- + +[source,java] +---- +include::{extrasdir}/entity/Instant.java[] +---- +==== + [[locking-optimistic-version-number]] -=== Dedicated version number +===== Dedicated version number The version number mechanism for optimistic locking is provided through a `@Version` annotation. @@ -64,7 +96,7 @@ If the version number is generated by the database, such as a trigger, use the a ==== [[locking-optimistic-timestamp]] -=== 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. @@ -110,6 +142,114 @@ include::{extrasdir}/locking-optimistic-version-timestamp-source-persist-example ---- ==== +[[locking-optimistic-versionless]] +===== Versionless optimistic locking + +Although the default `@Version` property optimistic locking mechanism is sufficient in many situations, +sometimes, you need rely on the actual database row column values to prevent *lost updates*. + +Hibernate supports a form of optimistic locking that does not require a dedicated "version attribute". +This is also useful for use with modeling legacy schemas. + +The idea is that you can get Hibernate to perform "version checks" using either all of the entity's attributes, or just the attributes that have changed. +This is achieved through the use of the +https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/OptimisticLocking.html[`@OptimisticLocking`] +annotation which defines a single attribute of type +https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/OptimisticLockType.html[`org.hibernate.annotations.OptimisticLockType`]. + +There are 4 available OptimisticLockTypes: + +`NONE`:: + optimistic locking is disabled even if there is a `@Version` annotation present +`VERSION` (the default):: + performs optimistic locking based on a `@Version` as described above +`ALL`:: + performs optimistic locking based on _all_ fields as part of an expanded WHERE clause restriction for the UPDATE/DELETE SQL statements +`DIRTY`:: + performs optimistic locking based on _dirty_ fields as part of an expanded WHERE clause restriction for the UPDATE/DELETE SQL statements + +[[locking-optimistic-versionless-all]] +====== Versionless optimistic locking using `OptimisticLockType.ALL` + +[[locking-optimistic-lock-type-all-example]] +.`OptimisticLockType.ALL` mapping example +==== +[source,java] +---- +include::{sourcedir}/OptimisticLockTypeAllTest.java[tag=locking-optimistic-lock-type-all-example,indent=0] +---- +==== + +When you need to modify the `Person` entity above: + +[[locking-optimistic-lock-type-all-update-example]] +.`OptimisticLockType.ALL` update example +==== +[source,java] +---- +include::{sourcedir}/OptimisticLockTypeAllTest.java[tag=locking-optimistic-lock-type-all-update-example,indent=0] +---- + +[source,SQL] +---- +include::{extrasdir}/locking-optimistic-lock-type-all-update-example.sql[] +---- +==== + +As you can see, all the columns of the associated database row are used in the `WHERE` clause. +If any column has changed after the row was loaded, there won't be any match, and a `StaleStateException` or an `OptimisticLockException` +is going to be thrown. + +[NOTE] +==== +When using `OptimisticLockType.ALL`, you should also use `@DynamicUpdate` because the `UPDATE` statement must take into consideration all the entity property values. +==== + +[[locking-optimistic-versionless-dirty]] +====== Versionless optimistic locking using `OptimisticLockType.DIRTY` + +The `OptimisticLockType.DIRTY` differs from `OptimisticLockType.ALL` +in that it only takes into consideration the entity properties that have changed +since the entity was loaded in the currently running Persistence Context. + +[[locking-optimistic-lock-type-dirty-example]] +.`OptimisticLockType.DIRTY` mapping example +==== +[source,java] +---- +include::{sourcedir}/OptimisticLockTypeDirtyTest.java[tag=locking-optimistic-lock-type-dirty-example,indent=0] +---- +==== + +When you need to modify the `Person` entity above: + +[[locking-optimistic-lock-type-dirty-update-example]] +.`OptimisticLockType.DIRTY` update example +==== +[source,java] +---- +include::{sourcedir}/OptimisticLockTypeDirtyTest.java[tag=locking-optimistic-lock-type-dirty-update-example,indent=0] +---- + +[source,SQL] +---- +include::{extrasdir}/locking-optimistic-lock-type-dirty-update-example.sql[] +---- +==== + +This time, only the database column that has changed was used in the `WHERE` clause. + +[NOTE] +==== +The main advantage of `OptimisticLockType.DIRTY` over `OptimisticLockType.ALL` +and the default `OptimisticLockType.VERSION` used implicitly along with the `@Version` mapping, +is that it allows you to minimize the risk of `OptimisticLockException` across non-overlapping entity property changes. + +When using `OptimisticLockType.DIRTY`, you should also use `@DynamicUpdate` because the `UPDATE` statement must take into consideration all the dirty entity property values, +and also the `@SelectBeforeUpdate` annotation so that detached entities are properly handled by the +https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/Session.html#update-java.lang.Object-[`Session#update(entity)`] operation. +==== + [[locking-pessimistic]] === Pessimistic diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/entity/Instant.java b/documentation/src/main/asciidoc/userguide/chapters/locking/extras/entity/Instant.java similarity index 100% rename from documentation/src/main/asciidoc/userguide/chapters/domain/extras/entity/Instant.java rename to documentation/src/main/asciidoc/userguide/chapters/locking/extras/entity/Instant.java diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/entity/Timestamp.java b/documentation/src/main/asciidoc/userguide/chapters/locking/extras/entity/Timestamp.java similarity index 100% rename from documentation/src/main/asciidoc/userguide/chapters/domain/extras/entity/Timestamp.java rename to documentation/src/main/asciidoc/userguide/chapters/locking/extras/entity/Timestamp.java diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/entity/Version.java b/documentation/src/main/asciidoc/userguide/chapters/locking/extras/entity/Version.java similarity index 100% rename from documentation/src/main/asciidoc/userguide/chapters/domain/extras/entity/Version.java rename to documentation/src/main/asciidoc/userguide/chapters/locking/extras/entity/Version.java diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/locking/locking-optimistic-lock-type-all-update-example.sql b/documentation/src/main/asciidoc/userguide/chapters/locking/extras/locking-optimistic-lock-type-all-update-example.sql similarity index 100% rename from documentation/src/main/asciidoc/userguide/chapters/domain/extras/locking/locking-optimistic-lock-type-all-update-example.sql rename to documentation/src/main/asciidoc/userguide/chapters/locking/extras/locking-optimistic-lock-type-all-update-example.sql diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/locking/locking-optimistic-lock-type-dirty-update-example.sql b/documentation/src/main/asciidoc/userguide/chapters/locking/extras/locking-optimistic-lock-type-dirty-update-example.sql similarity index 100% rename from documentation/src/main/asciidoc/userguide/chapters/domain/extras/locking/locking-optimistic-lock-type-dirty-update-example.sql rename to documentation/src/main/asciidoc/userguide/chapters/locking/extras/locking-optimistic-lock-type-dirty-update-example.sql diff --git a/documentation/src/main/docbook/mappingGuide/en-US/chapters/entity/Entity.xml b/documentation/src/main/docbook/mappingGuide/en-US/chapters/entity/Entity.xml index e180321998..c583956e24 100644 --- a/documentation/src/main/docbook/mappingGuide/en-US/chapters/entity/Entity.xml +++ b/documentation/src/main/docbook/mappingGuide/en-US/chapters/entity/Entity.xml @@ -249,7 +249,7 @@ -
+
Mapping optimistic locking