Multi Version Concurrency Control
In the event that your application has two threads that attempt to update the same record, the last one issued receives the following exception:
OConcurrentModificationException: Cannot update records
#X:Y in storage 'Z' because the version is not the latest.
Probably you are updating an old record or it has been
modified by another user (db=vA your=vB)
Every time you update a record, the version number for that record gets incremented by one. What this means is, when the instance that fails attempts to update the record, it finds that the version it is trying to update is behind what's current on the database.
Below are examples of how to properly manage version concurrency.
Database Retry API
ORID id = ...///
// As first parameter you set the number of wanted retry, at second parameter a lambda with your business logic
session.executeWithRetry(10, (currentSession) -> {
currentSession.begin();
OElement loaded = currentSession.load(id);
loaded.setProperty("two", "three");
currentSession.save(loaded);
currentSession.commit();
return null;
});
Database API Custom Retry
for (int retry = 0; retry < maxRetries; ++retry) {
try {
// APPLY CHANGES
document.field("name", "Luca");
database.save(document);
break;
} catch(ONeedRetryException e) {
// RELOAD IT TO GET LAST VERSION
document.reload();
}
}
Tinkerpop Graph API Custom Retry
for (int retry = 0; retry < maxRetries; ++retry) {
try {
// APPLY CHANGES
vertex.setProperty("name", "Luca");
vertex.addEdge("Buy", product);
break;
} catch(ONeedRetryException e) {
// RELOAD IT TO GET LAST VERSION
vertex.reload();
product.reload();
}
}
Transactions Custom Retry
There is a similar procedure used with transactions:
for (int retry = 0; retry < maxRetries; ++retry) {
database.begin();
try {
// CREATE A NEW ITEM
ODocument invoiceItem = new ODocument("InvoiceItem");
invoiceItem.field("price", 213231);
database.save(invoiceItem;
// ADD IT TO THE INVOICE
Collection<ODocument> items = invoice.field(items);
items.add(invoiceItem);
database(invoice);
database.commit();
break;
} catch(OTransactionException e) {
// RELOAD IT TO GET LAST VERSION
invoice.reload();
}
}
Where maxRetries
is the maximum number of attempts of reloading.
Running Transactions
Transactions are bound to a database. If you change the current database while a transaction is running, the deleted and saved objects remain attached to the original database transaction. When it commits, the objected are committed.
For instance,
ODatabaseDocument db1 =orientDB.open("db1","admin","admin"); // SETS CURRENT DB TO db1
db1.begin();
ODocument doc1 = new ODocument("Customer");
doc1.field("name", "Luca");
database.save(doc1); // OPERATION BOUND TO db1 TRANSACTION
ODatabaseDocument db2 = orientDB.open("db2","admin","admin"); // SETS CURRENT DB TO db2
ODocument doc2 = new ODocument("Provider");
doc2.field("name", "Chuck");
db2.save(doc2); // OPERATION BOUND TO db2 BECAUSE IT'S CURRENT
db1.activateOnCurrentThread();
db1.commit(); // COMMITS TRANSACTION FOR doc1 ONLY