skip to Main Content

I have encountered an issue in the application that I’m working with where in a single transaction I am trying to update a document in one collection,
and use the updated value in another document when creating it as I have added a bulk registration of the second document.

this results in TransientTransactionError and a WriteConflict log

This has kind of worked for single documents so far, until you have tried to repeat the process again.

Is this even possible?

I have tried using different propagation levels such as REQUIRES_NEW and NESTED (not supported) with no luck on the oneUpdater.update() method, originally it w as implemented without @Transactional

@Document
class One { 
String id;
int value;
}

@Document
class Two {
String id;
String currentOneValue;
}

class OneUpdater{
 int update() {
  // searches for single document with the same id and increments value by 1
  return mongoTemplate.findAndmodify().getValue();
}
}

class Service {
private final OneUpdater oneUpdater; // uses mongoTemplate.findAndModify to increment value by 1
private final TwoRepository twoRepository; extends MongoRepository
    @Transactional
    void createTwo {
     int value  = oneUpdater.update();
     Two t = new Two(UUID.randomUuid.toString(), value);
     
    twoRepository.save(t);

    }

}
Caused by: com.mongodb.MongoCommandException: Command failed with error 112 (WriteConflict): 'WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.' on server localhost:27017. The full response is {"errorLabels": ["TransientTransactionError"], "operationTime": {"$timestamp": {"t": 1651680481, "i": 2}}, "ok": 0.0, "errmsg": "WriteConflict error: this operation conflicted with another operation. Please retry your operation or multi-document transaction.", "code": 112, "codeName": "WriteConflict", "$clusterTime": {"clusterTime": {"$timestamp": {"t": 1651680481, "i": 2}}, "signature": {"hash": {"$binary": {"base64": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=", "subType": "00"}}, "keyId": 0}}}

2

Answers


  1. Chosen as BEST ANSWER

    The the solution to this was much simpler than I thought, Document One didn't store any meaningful data rather it supports Two in providing some additional metadata.

    My solution to this problem was to annotate the update() method with

    @Transactional(propagation = Propagation.NOT_SUPPORTED so my active transaction would be suspended, and update() would execute non-transactionally as I don't care too much about the data there and it stopped exceptions from being thrown

    class OneUpdater{
        @Transactional(propagation = Propagation.NOT_SUPPORTED
        int update() {
         // searches for single document with the same id and increments value by 1
         return mongoTemplate.findAndmodify().getValue();
        }
    }
    

  2. Well Mongo already gave you good advise or "… or multi-document transaction".

    Please see Spring example with configuring MongoTransactionManager https://spring.io/blog/2018/06/28/hands-on-mongodb-4-0-transactions-with-spring-data

    In this example operation modifies exactly 2 documents.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search