From eb47e6b3fa032686e5fb6ce99d3c92882c5206cf Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 23 Dec 2024 18:44:42 +0100 Subject: [PATCH] improve coverage of optimistic locking in the Short Guide --- .../src/main/asciidoc/introduction/Entities.adoc | 4 +--- .../src/main/asciidoc/introduction/Interacting.adoc | 10 ++++++++-- .../src/main/asciidoc/introduction/Tuning.adoc | 6 +++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/documentation/src/main/asciidoc/introduction/Entities.adoc b/documentation/src/main/asciidoc/introduction/Entities.adoc index 463a881d81fe..3aebef38e20f 100644 --- a/documentation/src/main/asciidoc/introduction/Entities.adoc +++ b/documentation/src/main/asciidoc/introduction/Entities.adoc @@ -458,9 +458,7 @@ It's easy to specify that the initial version should be assigned the number `1` int version = 1; // the initial version number ---- -Optimistic locks are verified by checking versions. -A version check is included in the `where` clause of every SQL `update` or `delete` statement for a versioned entity. -If a version check fails--that is, if no rows are updated--Hibernate throws an `OptimisticLockException` indicating that the current session is working with stale data--that is, that the entity was updated in some other unit of work. +Almost every entity which is frequently updated should have a version attribute. [TIP] // .Optimistic locking in Hibernate diff --git a/documentation/src/main/asciidoc/introduction/Interacting.adoc b/documentation/src/main/asciidoc/introduction/Interacting.adoc index c84e69e0ce2b..adfd3e99466e 100644 --- a/documentation/src/main/asciidoc/introduction/Interacting.adoc +++ b/documentation/src/main/asciidoc/introduction/Interacting.adoc @@ -301,9 +301,15 @@ The persistence context is fragile. If you receive an exception from Hibernate, you should immediately close and discard the current session. Open a new session if you need to, but throw the bad one away first. ==== +One very important kind of exception which can happen when data is shared between concurrent units of work is an _optimistic lock failure_. +Optimistic locks are verified by checking <>. +A version check is included in the `where` clause of every SQL `update` or `delete` statement for a versioned entity. +If a version check fails--that is, if no rows are updated--Hibernate infers that the entity was updated in some other unit of work and throws an `OptimisticLockException` to indicate that the current session is working with stale data. +As with other exceptions, this loss of synchronization between the persistence context and the database means that we must discard the current session. + [CAUTION] ==== -Some of these operations require slightly more care than others. +Some of these operations listed above require slightly more care than others. When you call `detach()`, `clear()`, `flush()`, or `refresh()`, you've already strayed from the narrow path. You didn't stray far--and you probably had a good reason for going there--but you're in territory where Hibernate just has to assume you know what you're doing. If you start to feel that this terrain is bogging you down, consider using a <>. @@ -1315,7 +1321,7 @@ Therefore, Hibernate has some APIs that streamline certain more complicated look | `byMultipleIds()` | Lets us load a _batch_ of ids at the same time |=== -[WARNING] +[NOTE] ==== Since the introduction of `FindOption` in JPA 3.2, `byId()` is now much less useful. ==== diff --git a/documentation/src/main/asciidoc/introduction/Tuning.adoc b/documentation/src/main/asciidoc/introduction/Tuning.adoc index 56df2a89cbd7..ade9d9af0c4e 100644 --- a/documentation/src/main/asciidoc/introduction/Tuning.adoc +++ b/documentation/src/main/asciidoc/introduction/Tuning.adoc @@ -924,7 +924,7 @@ When many transactions try to read and update the same data, the program might b There's two basic approaches to data concurrency in Hibernate: -- optimistic locking using `@Version` columns, and +- optimistic locking using <>, and - database-level pessimistic locking using the SQL `for update` syntax (or equivalent). In the Hibernate community it's _much_ more common to use optimistic locking, and Hibernate makes that incredibly easy. @@ -938,8 +938,8 @@ Indeed, the usual practice is to avoid having transactions that span user intera That said, there _is_ also a place for pessimistic locks, which can sometimes reduce the probability of transaction rollbacks. -Therefore, the `find()`, `lock()`, and `refresh()` methods of the reactive session accept an optional `LockMode`. -We can also specify a link:{doc-javadoc-url}/org/hibernate/LockMode.html[`LockMode`] for a query. +Therefore, the `find()`, `lock()`, and `refresh()` methods of the session accept an optional link:{doc-javadoc-url}/org/hibernate/LockMode.html[`LockMode`]. +We can also specify a `LockMode` for a query. The lock mode can be used to request a pessimistic lock, or to customize the behavior of optimistic locking: .Optimistic and pessimistic lock modes