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.
|
||||
|
||||
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]]
|
||||
=== 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 <<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]]
|
||||
==== `@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.
|
||||
|
||||
[[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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -249,7 +249,7 @@
|
|||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="entity-pojo-optlock">
|
||||
<section xml:id="locking-optimistic">
|
||||
<title>Mapping optimistic locking</title>
|
||||
|
||||
<para>
|
||||
|
|
Loading…
Reference in New Issue