Skip to content

Commit 4db4e4f

Browse files
committed
Review comments
1 parent cd0101a commit 4db4e4f

File tree

1 file changed

+61
-38
lines changed

1 file changed

+61
-38
lines changed

content/en/docs/refguide/runtime/optimistic-locking.md

Lines changed: 61 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,82 +4,105 @@ url: /refguide/optimistic-locking/
44
description: "Describes optimistic locking support."
55
---
66

7-
# What is Optimistic Locking
7+
## Introduction
88

9-
Optimistic locking is a strategy used in concurrent systems to prevent **lost updates** when multiple users or processes try to modify the same piece of data at the same time. The **optimistic** part comes from the assumption that conflicts are rare. Instead of locking the data immediately, it allows multiple users to read and potentially modify the same data concurrently. It only checks for conflicts at the very last moment, when an update is attempted.
9+
{{% alert color="info" %}}
10+
This feature is available from Mendix 11.5 and onwards.
11+
{{% /alert %}}
1012

11-
If a conflict is detected, meaning someone else modified the data since you last read it, your update is rejected, and you typically have to re-read the data and try again.
13+
Optimistic locking is a strategy used in concurrent systems to prevent **lost updates** when multiple users or processes try to modify the same piece of data at the same time. The **optimistic** part comes from the assumption that conflicts are rare. Instead of locking the data immediately, it allows multiple users to read and potentially modify the same data concurrently. It checks for conflicts only at the very last moment, when an update is attempted.
1214

13-
This feature is available from Mendix 10.5.0 and onwards.
15+
If a conflict is detected—meaning someone else has modified the data since you last read it—your update is rejected, and you typically have to re-read the data and try again.
1416

15-
# Behavior before Mendix 10.5.0 or when Optimistic Locking is disabled
17+
## Project With Optimistic Locking Disabled
1618

17-
Before Mendix 10.5.0 the runtime did no locking. When two modifications are saved then they are applied in order of processing. This is still the behavior when optimistic locking is disabled.
19+
When two modifications are saved, they are applied in the order of processing. Only changed attributes are written to the database. This means that if two objects with disjoint sets of changed attributes are committed, the changes are not overwritten.
1820

19-
# How to enable and use optimistic locking
21+
For example, if one user commits changes for `AttributeA` and `AttributeB` and another user commits changes for `AttributeB` and `AttributeC` for the same object, then both `AttributeA` and `AttributeC` are committed according to both users' changes. `AttributeB` is committed based on whichever change was committed last.
2022

21-
Optimistic locking can be enabled per Mendix application using `Runtime` tab in the App settings dialog:
23+
## Project With Optimistic Locking Enabled
24+
25+
The Mendix runtime implements optimistic locking by introducing a new attribute named `MxObjectVersion` with type `Long` to all entities tracking their version. The `MxObjectVersion` attribute is not write-protected. However, setting this value will **not** result in it being saved to the database. Its current value will be compared with the value for the same record in the database.
26+
27+
### How to Enable and Use Optimistic Locking
28+
29+
Optimistic locking can be enabled per Mendix application using the `Runtime` tab in the App settings dialog:
2230

2331
{{< figure src="/attachments/refguide/runtime/optimistic-locking/runtime-settings-dialog.png" >}}
2432

25-
After optimistic locking is enabled whenever a commit is executed, Mendix runtime will automatically ensure that the object that is committed was not already changed by another party after the committer read the object.
33+
After optimistic locking is enabled, whenever a commit is executed, the Mendix runtime will automatically ensure that the object that is committed was not already changed by another party after the committer retrieved the object.
34+
35+
### New Projects and Migration
36+
37+
In case an existing app already had the `MxObjectVersion` attribute, when optimistic locking is enabled a duplicate attribute will be reported in the Modeler. This must be fixed by renaming the existing attribute to another name. The system attribute cannot be renamed.
2638

27-
## New projects and migration
39+
### Behavior
2840

29-
In case an existing app already had the `MxObjectVersion` attribute, when optimistic locking enabled a duplicate attribute will be reported in the Modeler. This must be fixed by renaming the existing attribute to another name. The system attribute cannot be renamed.
41+
The following runtime actions are influenced by optimistic locking:
3042

31-
# Under the hood
43+
#### Create Object
3244

33-
Mendix runtime implements optimistic locking by introducing a new attribute named `MxObjectVersion` to all entities. When an object is committed, the `MxObjectVersion` of the committed object is compared to the existing data in the database. If the `MxObjectVersion` value does not match the one in the database, this means the object is modified by another party since it is last read. In this case runtime throws a `ConcurrentModificationRuntimeException`.
45+
Initialize the `MxObjectVersion` attribute to `0`.
3446

35-
When Optimistic Locking is enabled, each entity gets an additional system attribute with the name `MxObjectVersion` of type `Long`. This field is automatically populated with the correct value. The default value is `1` and this value will be automatically increased with every commit of that entity instance.
47+
#### Commit Object
3648

37-
Upon `update` and `delete`, the attribute value is from the object compared to the value available for this record in the database. If it is the same, then the update or delete will proceed. If it is different, which means the object is modified by another party since it is last read, a `ConcurrentModificationRuntimeException` is thrown, preventing the update or delete from proceeding. The `MxObjectVersion` attribute on the Mendix object is not write-protected. Setting this value however will **not** result in this value being saved into the database. Its current value will be used to compare it with the value for the same record in the database.
49+
When the `MxObjectVersion` attribute in the object being committed is different from the value in the database, or the object was deleted from the database, throw a `ConcurrentModificationRuntimeException`. Otherwise, proceed with the commit while incrementing `MxObjectVersion` by one.
3850

39-
## Impact on insert
51+
#### Delete Object
4052

41-
There is no impact on insert as this will just introduce the record in the database.
53+
When the `MxObjectVersion` attribute in the object being deleted is different from the value in the database, throw a `ConcurrentModificationRuntimeException`. Otherwise, proceed with the delete. If the object was already deleted, no error occurs.
4254

43-
## Impact on update
55+
## Performance Impact
4456

45-
When no concurrent modification occurs, update happens as before. However, when a concurrent modification is detected, the runtime will throw a `ConcurrentModificationRuntimeException`. This exception prevents the transaction from succeeding. If the entity instance was deleted before applying the update this would also result in `ConcurrentModificationRuntimeException`.
57+
Because of the version check performed during commit and delete, optimistic locking incurs some minor performance impact.
4658

47-
## Impact on delete
59+
## Handling Optimistic Locking Errors in Microflows
4860

49-
If the entity was updated before applying delete an optimistic lock error occurs. If the entity was deleted before applying delete no error occurs (as is the case without optimistic locking too).
61+
When an optimistic locking error occurs, the runtime log contains an entry similar to the following:
5062

51-
## Impact on performance
63+
```
64+
com.mendix.modules.microflowengine.MicroflowException: com.mendix.core.CoreRuntimeException: com.mendix.systemwideinterfaces.MendixRuntimeException: com.mendix.core.CoreException: com.mendix.core.CoreRuntimeException: com.mendix.systemwideinterfaces.MendixRuntimeException: com.mendix.systemwideinterfaces.connectionbus.data.ConcurrentModificationRuntimeException: Object of type 'MyFirstModule.MyEntity' with guid '3940649673949185' cannot be updated, as it is modified by someone else
65+
at MyFirstModule.MyMicroflow (Change : 'Change 'MyEntity'')
66+
```
5267

53-
This attribute is only added to the entities that are not derived from other entities. This way all entities will have this attribute (the derived entities will derive it from the parent entity). This causes every entity to have maximum one extra attribute in queries and an extra check upon update. There can be some performance impact, although it is expected to be minor.
68+
The above error shows that there was a `ConcurrentModificationRuntimeException` during execution of the change action `Change 'MyEntity'` of the microflow `MyFirstModule.MyMicroflow`. The object had the id `3940649673949185` and was of type `MyFirstModule.MyEntity`.
5469

55-
# Handling optimistic locking errors in Microflows
70+
Once a commit of an object causes an optimistic locking error, trying to commit the same object without reloading will always result in an optimistic locking error.
5671

57-
If the changes are still deemed valid, the action causing the optimistic locking error can be retried. To do that, error handling for that action should be changed to use either `Custom with Rollback` or `Custom without Rollback`. Then if `$latestError/ErrorType` is `com.mendix.systemwideinterfaces.connectionbus.data.ConcurrentModificationRuntimeException`
58-
then this means an optimistic locking error is occured. To retry the operation a fresh copy of the object should be loaded from database, then existing changes should be applied onto that object and the operation should be invoked again. Once committing an object caused optimistic locking error, trying to commit the same object without reloading will always result in optimistic locking error.
72+
If the changes are still deemed valid, the action causing the optimistic locking error should be retried:
5973

60-
An example can be seen below. Change/Commit action has error handling `Custom without Rollback`. If an optimistic locking error is detected, the object is reloaded from database, changes applied again and commit is retried.
74+
1. Change the error handling for that action to either `Custom with Rollback` or `Custom without Rollback`, and do the following steps in the error flow
75+
2. If `$latestError/ErrorType` is `com.mendix.systemwideinterfaces.connectionbus.data.ConcurrentModificationRuntimeException`
76+
3. Retrieve a fresh copy of the object from the database
77+
4. Apply the original changes onto the retrieved copy
78+
5. Invoke the operation again
79+
80+
An example can be seen below. The change action has error handling `Custom without Rollback`. If an optimistic locking error is detected, the object is reloaded from the database, changes are applied again and the change action is retried.
6181

6282
{{< figure src="/attachments/refguide/runtime/optimistic-locking/retry-example.png" >}}
6383

64-
Check [documentation](https://docs.mendix.com/refguide/error-handling-in-microflows/) about error handling to get more info about differences between `Custom with Rollback` and `Custom without Rollback`.
84+
Check the [documentation](https://docs.mendix.com/refguide/error-handling-in-microflows/) about error handling to find more information about differences between `Custom with Rollback` and `Custom without Rollback`.
6585

66-
# Handling optimistic locking errors in Java actions
86+
## Handling Optimistic Locking Errors in Java Actions
6787

68-
In Java actions if an optimistic locking error is detected similar steps described in `Handling Handling optimistic locking errors in Microflows` can be used for retrying. The `com.mendix.systemwideinterfaces.connectionbus.data.ConcurrentModificationRuntimeException` exception will not be the top level exception thrown by Mendix runtime. It will be wrapped in another exception, so the `cause` chain of caught exception should be inspected.
88+
In Java actions an optimistic locking error can be handled by similar steps described in [Handling Optimistic Locking Errors in Microflows]. However, the `com.mendix.systemwideinterfaces.connectionbus.data.ConcurrentModificationRuntimeException` exception will not be the top level exception thrown by the Mendix runtime. It will be wrapped in another exception, so the `cause` chain of caught exceptions should be inspected.
6989

70-
# Handling optimistic locking errors in the client
90+
## Handling Optimistic Locking Errors in the Client
7191

7292
If the optimistic locking error is propagated to the client, then an error dialog is shown as follows:
7393

7494
{{< figure src="/attachments/refguide/runtime/optimistic-locking/optimistic-locking-error-dialog.png" >}}
7595

76-
The runtime log file contains an entry similar to following:
96+
To handle the optimistic locking error one of the following approaches can be used:
7797

78-
```
79-
com.mendix.modules.microflowengine.MicroflowException: com.mendix.core.CoreRuntimeException: com.mendix.systemwideinterfaces.MendixRuntimeException: com.mendix.core.CoreException: com.mendix.core.CoreRuntimeException: com.mendix.systemwideinterfaces.MendixRuntimeException: com.mendix.systemwideinterfaces.connectionbus.data.ConcurrentModificationRuntimeException: Object of type 'MyFirstModule.MyEntity' with guid '3940649673949185' cannot be updated, as it is modified by someone else
80-
at MyFirstModule.MyMicroflow (Change : 'Change 'MyEntity'')
81-
```
98+
### Single `Save` Button
99+
100+
In this case the user can refresh the whole page, but this causes all their changes to be lost.
101+
102+
### `Save` Button With a Separate `Refresh` Button
103+
104+
A separate `Refresh` button that retrieves the latest object state from the database and applies the original changes to the retrieved object. After clicking the `Refresh` button, the user can inspect the latest state and can click the `Save` button again. This would be similar to a single retry from [Handling Optimistic Locking Errors in Microflows].
82105

83-
Above error shows that there was a `ConcurrentModificationRuntimeException` during execution of the change action `Change 'MyEntity'` of the microflow `MyFirstModule.MyMicroflow. The object had the id ~3940649673949185` and was of type `MyFirstModule.MyEntity`.
106+
### Custom `Save` Button
84107

85-
The only option is refreshing the page which would cause losing all the changes.
108+
A custom `Save` button that retries saving object using similar steps described in [Handling Optimistic Locking Errors in Microflows], to retry until successful.

0 commit comments

Comments
 (0)