Event Sourcing (19): Implement optimistic locking in InMemoryRepository

July 26 15:52~16:39

截圖 2022-07-23 下午9.26.00

▲Figure 1: Optimistic lock test case


This series of articles was originally written by Teddy in order to create a course example of [ Event Sourcing and Command Query Responsibility Separation Architecture Implementation Class ]. The course example has been completed, and the serialization of this series of articles has ended. A few days ago, Teddy went back and changed the example of the course to a new way of writing. Before the modification, I ran the test first, but there was a mistake!

After a closer look, I remember that Teddy injected InMemoryTagRepository into the test case when he practiced before. It does not support optimistic locking, so the original optimistic locking test case will fail. Just switch back to the normal Repository. This problem has also been encountered before. Pass.

But this time Teddy suddenly thought: “Why can’t InMemoryRepository support optimistic locking?” It took a few minutes to change the code, and the test case passed. I will add an article today to talk about how to make InMemoryRepository support optimistic locking.


Implement optimistic locking

Teddy introduced in < Event Sourcing (7): Optimistic Locking > how to implement optimistic locking in relational databases and event sourcing databases, basically adding a Version field to Aggregate, every time Aggregate is stored Compare the value of Version on it with the value in the database. If they are equal, it means that no one else has written the Aggregate since it was last read from the database, so its current version is the latest and can be stored directly in the database. On the contrary, it means that the current version of Aggregate is old and cannot be stored, and the system will throw an optimistic locking failure exception.

Please refer to the test case in Figure 1, and take out two identical objects, tagV1 and tagV2, from the tagRepository according to the same tagId. First rename tagV1 and save it, and then save tagV2. At this time, the Version value of tagV2 will be less than the value stored in tagRepository, so a RepositorySaveException exception will be thrown.

First modify the findById method of InMemoryTageRepository , as shown in Figure 2. Originally, the InMemoryTagRepository stored the Tag in the List, and the reference of the Tag in the memory returned by findById. This direct return memory reference object cannot test optimistic locking, because tagV1 and tagV2 in Figure 1 will refer to the same tag, that is to say, changing tagV1 will change the value of tagV2 at the same time. So findById should be changed to return a new Tag object instead of a reference to the original Tag object.

截圖 2022-07-26 下午4.20.56

▲Figure 2: Modify the findById method of InMemoryTagRepository to support optimistic locking

Next, modify the save method of InMemoryTagRepository, as shown in Figure 3. If the tag to be stored already exists in the InMemoryTagRepository, and its version is not equal to the version in memory, a RepositorySaveException is thrown. On the contrary, first remove the tag from the memory (if not removed, the same Tag will appear twice in the InMemoryTagRepository), then increment its version by 1, then store it, and finally clear the field events on the tag .

截圖 2022-07-23 下午9.29.37

▲Figure 3: Modify the sava method of InMemoryTagRepository to support optimistic locking

That’s it, it’s that simple.


in conclusion

This episode introduces how to make InMemoryRepository also have optimistic locking, but the InMemoryTagRepository implemented by Teddy here only supports the storage method of State Sourcing, and does not support Event Sourcing. If you want to implement InMemoryEventSourcingRepository, it’s basically not too difficult, you should only need:

  • Change the data structure from List to Map<String, List<DomainEvent>>, the Key of Map is Event Stream Name, and Value is the field of Aggregate. As for the version of Aggregate, it is the size of List<DomainEvent>.
  • When storing Aggregate, there is no need to update the version number, because the version number of Aggregate when reading (fndById) is the size of the List<DomainEvent> to which it belongs.

The implementation of InMemoryEventSourcingRepository is left to the villagers to practice by themselves.


Youzo’s inner monologue: This episode is an extra part.

This article is reprinted from https://teddy-chen-tw.blogspot.com/2022/07/19inmemoryrepository.html
This site is for inclusion only, and the copyright belongs to the original author.

Leave a Comment