mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-08-16 22:23:33 +00:00
docs: update version number
This commit is contained in:
+46
-31
@@ -21,7 +21,7 @@ Ensure data consistency and integrity by tracking changes to data with version n
|
|||||||
|
|
||||||
## Explanation
|
## 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.
|
> 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.
|
||||||
|
|
||||||
@@ -43,10 +43,10 @@ We have a `Book` entity, which is versioned, and has a copy-constructor:
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class Book {
|
public class Book {
|
||||||
|
|
||||||
private long id;
|
private long id;
|
||||||
private String title = "";
|
private String title = "";
|
||||||
private String author = "";
|
private String author = "";
|
||||||
|
|
||||||
private long version = 0; // version number
|
private long version = 0; // version number
|
||||||
|
|
||||||
public Book(Book book) {
|
public Book(Book book) {
|
||||||
@@ -62,6 +62,7 @@ We also have `BookRepository`, which implements concurrency control:
|
|||||||
|
|
||||||
```java
|
```java
|
||||||
public class BookRepository {
|
public class BookRepository {
|
||||||
|
|
||||||
private final Map<Long, Book> collection = new HashMap<>();
|
private final Map<Long, Book> collection = new HashMap<>();
|
||||||
|
|
||||||
public void update(Book book) throws BookNotFoundException, VersionMismatchException {
|
public void update(Book book) throws BookNotFoundException, VersionMismatchException {
|
||||||
@@ -95,42 +96,56 @@ public class BookRepository {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Here's the concurrency control in action:
|
Here's the version number pattern in action:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
var bookId = 1;
|
public class App {
|
||||||
// Alice and Bob took the book concurrently
|
|
||||||
final var aliceBook = bookRepository.get(bookId);
|
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||||
final var bobBook = bookRepository.get(bookId);
|
|
||||||
|
|
||||||
aliceBook.setTitle("Kama Sutra"); // Alice has updated book title
|
public static void main(String[] args) throws
|
||||||
bookRepository.update(aliceBook); // and successfully saved book in database
|
BookDuplicateException,
|
||||||
LOGGER.info("Alice updates the book with new version {}", aliceBook.getVersion());
|
BookNotFoundException,
|
||||||
|
VersionMismatchException {
|
||||||
|
var bookId = 1;
|
||||||
|
|
||||||
// now Bob has the stale version of the book with empty title and version = 0
|
var bookRepository = new BookRepository();
|
||||||
// while actual book in database has filled title and version = 1
|
var book = new Book();
|
||||||
bobBook.setAuthor("Vatsyayana Mallanaga"); // Bob updates the author
|
book.setId(bookId);
|
||||||
try {
|
bookRepository.add(book); // adding a book with empty title and author
|
||||||
LOGGER.info("Bob tries to update the book with his version {}", bobBook.getVersion());
|
LOGGER.info("An empty book with version {} was added to repository", book.getVersion());
|
||||||
bookRepository.update(bobBook); // Bob tries to save his book to database
|
|
||||||
} catch (VersionMismatchException e) {
|
// Alice and Bob took the book concurrently
|
||||||
// Bob update fails, and book in repository remained untouchable
|
final var aliceBook = bookRepository.get(bookId);
|
||||||
LOGGER.info("Exception: {}", e.getMessage());
|
final var bobBook = bookRepository.get(bookId);
|
||||||
// Now Bob should reread actual book from repository, do his changes again and save again
|
|
||||||
|
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:
|
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
|
|
||||||
```
|
```
|
||||||
|
14:51:04.119 [main] INFO com.iluwatar.versionnumber.App -- An empty book with version 0 was added to repository
|
||||||
## Class diagram
|
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
|
## Applicability
|
||||||
|
|
||||||
@@ -140,9 +155,9 @@ Exception: Tried to update stale version 0 while actual version is 1
|
|||||||
|
|
||||||
## Tutorials
|
## Tutorials
|
||||||
|
|
||||||
* [JPA entity versioning - byteslounge.com](https://www.byteslounge.com/tutorials/jpa-entity-versioning-version-and-optimistic-locking)
|
* [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)
|
* [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)
|
* [Versioning Entity (java2s.com)](http://www.java2s.com/Tutorial/Java/0355__JPA/VersioningEntity.htm)
|
||||||
|
|
||||||
## Known Uses
|
## Known Uses
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user