HHH-11186 - Add examples for all Hibernate annotations
Move optimistic locking mapping to the Locking chapter
This commit is contained in:
parent
baf194d422
commit
378009d5e1
|
@ -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`
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue