Skip to content

SpringBoot application outlining usage of different MongoDB Data Models for atomic operations / transactions. Referring to and extending the MongoDB Model Data for Atomic Operations example.

christophstrobl/mongodb-bookstore

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Welcome to the Fantasy Bookstore

The Fantasy Bookstore is a tiny SpringBoot application outlining usage of different MongoDB Data Models for atomic operations. The Bookstore refers to and extends the Model Data for Atomic Operations example.

Use Application Profiles to activate the different approaches.

Profile Description
sa Synchronous Atomic Operations with denormalized Data Model
stxn Synchronous Multi Document Transactions using just the native MongoClient
stx Synchronous Spring managed Multi Document Transactions
rtx Reactive Multi Document Transactions
rcs Active this profile along with one of the transactional (stx, rtx) ones to subscribe to changes on the order collection.
retry Activate this profile to retry failed transactions via Spring Retry.
reset Reset the initial set of collections and pre fill it with test data

Web Endpoints

URL Sample Description
GET :8080/books http :8080/books List all books.
GET :8080/book/{book} http :8080/book/bb4e114f A single Book.
POST :8080/book/{book}/order?customer= http POST :8080/book/bb4e114f/order?customer=christoph Place an order for a book.

Synchronous Atomic Operations with denormalized Data Model

The denormalized Data Model keeps all required data in one place, the Document. Hence all updates of the one document are atomic. Each and every Order is tracked by checkout within the Book itself.

{
     "_id" : "bb4e114f",
     "title" : "The Painted Man",
     "author" : [ "Peter V. Brett" ],
     "published_date" : "2009-08-01",
     "pages" : 544,
     "language" : "English",
     "publisher_id" : "Harper Collins Publishers",
     "available" : 3,
     "checkout" : [ { "by": "cstrobl", "date" : "2018-08-27T10:11:59.853Z" } ]
 }

Spring Profile: sa
MongoDB Collections: books
Components: AtomicOrderService, SyncBookstoreHandler

Synchronous Spring Managed Multi Document Transactions

The transactional approach splits data between Book and Order whereas the Order references the Book via a DBRef. Still the number of available copies is kept within the books collection.

{
    "_id" : "bb4e114f",
    "title" : "The Painted Man",
    "author" : [ "Peter V. Brett" ],
    "published_date" : "2009-08-01",
    "pages" : 544,
    "language" : "English",
    "publisher_id" : "Harper Collins Publishers",
    "available" : 3
}
{
    "by" : "cstrobl",
    "date" : "2018-08-27T10:11:59.853Z",
    "books" : [ { "$ref" : "books", "$id" : "bb4e114f" } ]
}

Spring Profile: stx
MongoDB Collections: books, order
Components: TransactionalOrderService, SyncBookstoreHandler

Synchronous Multi Document Transactions with native MongoClient

Just as in the sample above data is split between Book and Order whereas the Order references the Book via a DBRef. However, here we're using the native operations of MongoClient and ClientSession to run the transaction.

Spring Profile: stxn
MongoDB Collections: books, order
Components: NativeMongoTransactionalOrderService, SyncBookstoreHandler

Reactive Multi Document Transactions

Just as the synchronous transactional approach data is split between Book and Order, this time using a reactive API for processing the checkout inside a transaction.

{
    "_id" : "bb4e114f",
    "title" : "The Painted Man",
    "author" : [ "Peter V. Brett" ],
    "published_date" : "2009-08-01",
    "pages" : 544,
    "language" : "English",
    "publisher_id" : "Harper Collins Publishers",
    "available" : 3
}
{
    "by" : "cstrobl",
    "date" : "2018-08-27T10:11:59.853Z",
    "books" : [ { "$ref" : "books", "$id" : "bb4e114f" } ]
}

Spring Profile: rtx
MongoDB Collections: books, order
Components: ReactiveOrderService, ReactiveBookstoreHandler

Retry Transactions

It may happen that multiple transactions try to alter the very same document which leads to write conflicts and therefore the abortion of the transaction.

This scenario can be provoked by:

rs0:PRIMARY> session = db.getMongo().startSession({ "mode" : "primary" });
rs0:PRIMARY> session.startTransaction();
rs0:PRIMARY> session.getDatabase("fantasy-bookstore").books.update({ "_id" : "f430cb49", "available" : { "$gt" : 0 } },  { "$inc" : { "available" : -1 } });
  • Call the order endpoint
~ $ http POST :8080/book/f430cb49/order?customer=cstrobl
  • The Application will retry the operation for 3 times with 5 seconds delay in between.
  • Switch to Mongo Shell again and commit the transaction within time to have the other one succeed as well.
rs0:PRIMARY> session.commitTransaction();

Spring Profile: stx,retry
MongoDB Collections: books, order
Components: TransactionalOrderService, SyncBookstoreHandler, RetryTemplate

Requirements

Java

The application requires Java 8 (or better).

MongoDB

The Application requires MongoDB 4.0 or better running as Replica Set.

Project Lombok

Some of the code uses Project Lombok. Make sure to have it.

About

SpringBoot application outlining usage of different MongoDB Data Models for atomic operations / transactions. Referring to and extending the MongoDB Model Data for Atomic Operations example.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages