Preventing Lost Updates

Objective

After completing this lesson, you will be able to use Etags to protect against data loss

Concurrency Control

In the following, we want to get an overview of the options that CAP provides to ensure data integrity when concurrent modifications are executed simultaneously.

The CAP runtimes support different ways to avoid lost-update situations as documented in the following video.

Optimistic Locking

We start with the optimistic locking concept, which is based on ETags (entity tags). To enable ETags for a model entity, add the @odata.etag annotation to an element of the entity definition.

In the example shown, the modifiedAt element from the managed aspect is defined as ETag element for both the Books entity and the Authors entity. The annotate directive is used for this, which allows existing definitions to be annotated.

Note

Elements whose content changes uniquely each time a data record is updated are suitable as ETag element. Therefore, the modifiedAt element of the predefined managed aspect is a good candidate. You could also use update counters or UUIDs, which are recalculated on each update.

The idea of an ETag is to identify a specific version of an entity, in our example the version of a book or an author. This can be used to ensure the integrity of the data, as explained in the following example, without using locks.

Assume we retrieve a specific author via the following request because we want to change his or her data:

Code Snippet
1
GET Authors(18f76942-bfb3-40c5-8300-f999f14e9cc2)

With this request, the version of the author, i.e. the value of the ETag element modifiedAt, is automatically returned via the ETag HTTP response header, for example:

Code Snippet
1
ETag: W/"2024-03-15T11:30:48.069Z"

To write back data changed on the author, the received ETag value is used as follows in the If-Match HTTP header of the corresponding change request:

Code Snippet
1234567
PUT Authors(18f76942-bfb3-40c5-8300-f999f14e9cc2) If-Match: W/"2024-03-15T11:30:48.069Z" Content-Type: application/json { ... }

CAP then checks whether the content of the modifiedAt element has changed in the meantime. If not, the author data is changed in the database and the modifiedAt ETag field is updated. If yes, this means that the author has been changed via another request since the data was read. CAP therefore aborts the change request and sets the status code 412 (Precondition Failed) for the HTTP response. The response body contains an error similar to the following:

Code Snippet
12345
"error": { "code": "412", "message": "Precondition Failed", "@Common.numericSeverity": 4 }

Pessimistic Locking

Optimistic locking ensures data integrity in the event of concurrent modifications through different requests.

Pessimistic locking, on the other hand, ensures data integrity in the event of concurrent modifications through concurrent transactions. Pessimistic locking allows you to lock data so that other transactions are blocked from changing the data in any way.

CAP leverages database locks for pessimistic locking, whereby a distinction is made between exclusive locks and shared locks.

Exclusively locked data records can neither be changed nor read by other transactions. Exclusive locks are set when the data records are read from the database. The query API of CAP provides the forUpdate() method for this purpose.

Note

Constructing and executing queries will be discussed later.

Shared locks also prevent concurrent updates by parallel transactions. However, they allow all transactions to read the locked data records.

To set shared locks, the query API provides the forShareLock() method.

Acquired locks (whether exclusive or shared) are released when the current transaction is completed, i.e. committed or rolled back.

Note

Pessimistic locking is not supported by SQLite.

Demonstration & Exercise: Add Optimistic Concurrency Control

Note

As exercise, carry out the step-by-step instructions in the following demonstration yourself in the SAP Business Application Studio.

As a starting point for the exercise, use the outcome of the previous exercise Implement Input Validation if you have successfully completed it. Alternatively, you can also use the branch 8_input_validation from the following GitHub repository as a starting point:

https://github.com/SAP-samples/cap-development-learning-journey

The complete implementation of the simulation can be found in the 9_concurrency_control branch of the GitHub repository.

Detailed information on the content of the repository and how to use it can be found here.

Watch the video to see how to add optimistic concurrency control.

Log in to track your progress & complete quizzes