Skip to content

Commit

Permalink
docs: update version number
Browse files Browse the repository at this point in the history
  • Loading branch information
iluwatar committed May 27, 2024
1 parent 5d44152 commit 3eb5813
Showing 1 changed file with 48 additions and 33 deletions.
81 changes: 48 additions & 33 deletions version-number/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Ensure data consistency and integrity by tracking changes to data with version n

## Explanation

Real world example
Real-world example

> Consider a library system where multiple librarians can update the details of books simultaneously. Each book entry in the library's database has a version number. When a librarian wants to update a book's details, the system checks the version number of the entry. If the version number matches the current version in the database, the update proceeds, and the version number is incremented. If the version number has changed, it means another librarian has already updated the book details, prompting the system to notify the librarian of the conflict and suggesting a review of the latest changes. This ensures that updates do not overwrite each other unintentionally, maintaining data integrity and consistency.
Expand All @@ -43,10 +43,10 @@ We have a `Book` entity, which is versioned, and has a copy-constructor:
@Getter
@Setter
public class Book {

private long id;
private String title = "";
private String author = "";

private long version = 0; // version number

public Book(Book book) {
Expand All @@ -62,6 +62,7 @@ We also have `BookRepository`, which implements concurrency control:

```java
public class BookRepository {

private final Map<Long, Book> collection = new HashMap<>();

public void update(Book book) throws BookNotFoundException, VersionMismatchException {
Expand Down Expand Up @@ -95,42 +96,56 @@ public class BookRepository {
}
```

Here's the concurrency control in action:
Here's the version number pattern in action:

```java
var bookId = 1;
// Alice and Bob took the book concurrently
final var aliceBook = bookRepository.get(bookId);
final var bobBook = bookRepository.get(bookId);

aliceBook.setTitle("Kama Sutra"); // Alice has updated book title
bookRepository.update(aliceBook); // and successfully saved book in database
LOGGER.info("Alice updates the book with new version {}", aliceBook.getVersion());

// now Bob has the stale version of the book with empty title and version = 0
// while actual book in database has filled title and version = 1
bobBook.setAuthor("Vatsyayana Mallanaga"); // Bob updates the author
try {
LOGGER.info("Bob tries to update the book with his version {}", bobBook.getVersion());
bookRepository.update(bobBook); // Bob tries to save his book to database
} catch (VersionMismatchException e) {
// Bob update fails, and book in repository remained untouchable
LOGGER.info("Exception: {}", e.getMessage());
// Now Bob should reread actual book from repository, do his changes again and save again
public class App {

private static final Logger LOGGER = LoggerFactory.getLogger(App.class);

public static void main(String[] args) throws
BookDuplicateException,
BookNotFoundException,
VersionMismatchException {
var bookId = 1;

var bookRepository = new BookRepository();
var book = new Book();
book.setId(bookId);
bookRepository.add(book); // adding a book with empty title and author
LOGGER.info("An empty book with version {} was added to repository", book.getVersion());

// Alice and Bob took the book concurrently
final var aliceBook = bookRepository.get(bookId);
final var bobBook = bookRepository.get(bookId);

aliceBook.setTitle("Kama Sutra"); // Alice has updated book title
bookRepository.update(aliceBook); // and successfully saved book in database
LOGGER.info("Alice updates the book with new version {}", aliceBook.getVersion());

// now Bob has the stale version of the book with empty title and version = 0
// while actual book in database has filled title and version = 1
bobBook.setAuthor("Vatsyayana Mallanaga"); // Bob updates the author
try {
LOGGER.info("Bob tries to update the book with his version {}", bobBook.getVersion());
bookRepository.update(bobBook); // Bob tries to save his book to database
} catch (VersionMismatchException e) {
// Bob update fails, and book in repository remained untouchable
LOGGER.info("Exception: {}", e.getMessage());
// Now Bob should reread actual book from repository, do his changes again and save again
}
}
}
```

Program output:

```java
Alice updates the book with new version 1
Bob tries to update the book with his version 0
Exception: Tried to update stale version 0 while actual version is 1
```

## Class diagram

![Version Number](./etc/version-number.urm.png "Version Number pattern class diagram")
14:51:04.119 [main] INFO com.iluwatar.versionnumber.App -- An empty book with version 0 was added to repository
14:51:04.122 [main] INFO com.iluwatar.versionnumber.App -- Alice updates the book with new version 1
14:51:04.122 [main] INFO com.iluwatar.versionnumber.App -- Bob tries to update the book with his version 0
14:51:04.123 [main] INFO com.iluwatar.versionnumber.App -- Exception: Tried to update stale version 0 while actual version is 1
```

## Applicability

Expand All @@ -140,9 +155,9 @@ Exception: Tried to update stale version 0 while actual version is 1

## Tutorials

* [JPA entity versioning - byteslounge.com](https://www.byteslounge.com/tutorials/jpa-entity-versioning-version-and-optimistic-locking)
* [Optimistic Locking in JPA - Baeldung](https://www.baeldung.com/jpa-optimistic-locking)
* [Versioning Entity - java2s.com](http://www.java2s.com/Tutorial/Java/0355__JPA/VersioningEntity.htm)
* [JPA entity versioning (byteslounge.com)](https://www.byteslounge.com/tutorials/jpa-entity-versioning-version-and-optimistic-locking)
* [Optimistic Locking in JPA (Baeldung)](https://www.baeldung.com/jpa-optimistic-locking)
* [Versioning Entity (java2s.com)](http://www.java2s.com/Tutorial/Java/0355__JPA/VersioningEntity.htm)

## Known Uses

Expand Down

0 comments on commit 3eb5813

Please sign in to comment.