Current approach to working with transactions in RMB
To enable the work with a database in FOLIO project there is a custom solution implemented on top of the VERT.X Postgres Client. The main feature of working with RMB and VERT.X is the usage of the asynchronous approach. Sequential execution of operations requires handling the completion of each operation and occurring errors. Each subsequent operation can be executed only if the previous one is succeeded. In order to maintain data consistency there is a need to execute the operations in transaction and be able to rollback the changes in case an error occurred. At the moment, this possibility is implemented as follows:
...
The First and the last operations the RMB PostgresClient does automatically.
Example method with two operation in scope of one transaction
Code Block | ||||
---|---|---|---|---|
| ||||
public Future<Void> example() { Future future = Future.future(); PostgresClient client = PostgresClient.getInstance(vertx, tenantId); // start tx client.startTx(tx -> { // first operation client.get(tx, "upload_definition", UploadDefinition.class, new Criterion(), true, false, getHandler -> { if (getHandler.succeeded()) { // second operation client.save(tx, "upload_definition", UUID.randomUUID().toString(), getHandler.result(), saveHandler -> { if (saveHandler.succeeded()) { client.endTx(tx, endHandler -> { if (endHandler.succeeded()) { future.succeeded(); } else { client.rollbackTx(tx, rollbackHandler -> { future.fail(getHandler.cause()); }); } }); } else { client.rollbackTx(tx, rollbackHandler -> { future.fail(getHandler.cause()); }); } }); } else { client.rollbackTx(tx, rollbackHandler -> { future.fail(getHandler.cause()); }); } }); }); return future; } |
Locking tables in a database
When developing a slightly more complex business logic, the difficulty arises in the fact that certain operations may take some time and, accordingly, at this moment there is a possibility that it will be necessary to process another such request. Without locking a record in the database, there is a high probability of “lost changes” when the second request overwrites the request overwrites the changes made by the first one. Since Since VERTX.X is asynchronous, any locks and synchronous code executions are unacceptable, and the Persistence Context is absent. The most obvious solution is solution is to use locks on the record in the database using the “SELECT FOR UPDATE” statement. Accordingly, to perform a safe update of the record in the database, you shouldyou should:
- Create Transaction Object
- Select data from database for update (using “SELECT FOR UPDATE”)
- Do some kind of business logic operation
- Update entity in database
- Complete transaction
...