HHH-11186 - Add examples for all Hibernate annotations

Move optimistic locking mapping to the Locking chapter
This commit is contained in:
Vlad Mihalcea 2017-05-25 17:27:35 +03:00
parent baf194d422
commit 378009d5e1
9 changed files with 145 additions and 144 deletions

View File

@ -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. 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 <<chapters/domain/entity.adoc#entity-pojo-optlock, Optimistic locking mapping>> section for more info. See the <<chapters/locking/Locking.adoc#locking-optimistic, Optimistic locking mapping>> section for more info.
[[annotations-hibernate]] [[annotations-hibernate]]
=== Hibernate annotations === 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. 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. 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 <<chapters/domain/entity.adoc#entity-pojo-optlock-versionless, Versionless optimistic locking>> section for more info. See the <<chapters/locking/Locking.adoc#locking-optimistic-versionless, Versionless optimistic locking>> section for more info.
[[annotations-hibernate-orderby]] [[annotations-hibernate-orderby]]
==== `@OrderBy` ==== `@OrderBy`

View File

@ -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 <<chapters/domain/identifiers.adoc#identifiers,Identifiers>> chapter. For details on mapping the identifier, see the <<chapters/domain/identifiers.adoc#identifiers,Identifiers>> 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]] [[entity-sql-query-mapping]]
==== Mapping the entity to a SQL query ==== Mapping the entity to a SQL query

View File

@ -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. Hibernate provides mechanisms for implementing both types of locking in your applications.
[[locking-optimistic]]
=== Optimistic === Optimistic
When your application uses long transactions or conversations that span several database transactions, 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. 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]] [[locking-optimistic-version-number]]
=== Dedicated version number ===== Dedicated version number
The version number mechanism for optimistic locking is provided through a `@Version` annotation. 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]] [[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. 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. 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]] [[locking-pessimistic]]
=== Pessimistic === Pessimistic

View File

@ -249,7 +249,7 @@
</para> </para>
</section> </section>
<section xml:id="entity-pojo-optlock"> <section xml:id="locking-optimistic">
<title>Mapping optimistic locking</title> <title>Mapping optimistic locking</title>
<para> <para>