Java 中的版本号模式:在 Java 应用程序中实现强大的版本管理
大约 3 分钟
也称为
- 实体版本控制
- 版本控制
版本号设计模式的意图
通过使用版本号跟踪更改,确保 Java 应用程序中的数据一致性和完整性,这是并发数据管理的关键组成部分。
版本号模式的详细解释,附带实际案例
实际案例
考虑一个图书馆系统,多个图书管理员可以同时更新书籍的详细信息。图书馆数据库中的每个书籍条目都有一个版本号。当图书管理员想要更新书籍的详细信息时,系统会检查条目的版本号。如果版本号与数据库中的当前版本匹配,则更新将继续进行,版本号将递增。如果版本号已更改,则表示另一个图书管理员已更新了书籍详细信息,系统将提示图书管理员注意冲突,并建议查看最新更改。这样可以确保更新不会意外覆盖彼此,从而保持数据完整性和一致性。
简单地说
Java 中的版本号模式为并发更新提供了强大的保护,确保分布式系统中的可靠数据版本控制。
维基百科说
版本号模式是一种用于管理数据库和其他数据存储中对数据的并发访问的技术。它涉及为每个记录关联一个版本号,每次更新记录时都会递增该版本号。这种模式有助于确保当多个用户或进程尝试同时更新相同数据时,可以检测和解决冲突。
Java 中版本号模式的编程示例
Alice 和 Bob 正在处理存储在数据库中的书籍。我们的两位英雄同时进行更改,我们需要一些机制来防止他们互相覆盖。
我们有一个 Book
实体,它是版本化的,并有一个复制构造函数
@Getter
@Setter
public class Book {
private long id;
private String title = "";
private String author = "";
private long version = 0; // version number
public Book(Book book) {
this.id = book.id;
this.title = book.title;
this.author = book.author;
this.version = book.version;
}
}
我们还有 BookRepository
,它实现了并发控制
public class BookRepository {
private final Map<Long, Book> collection = new HashMap<>();
public void update(Book book) throws BookNotFoundException, VersionMismatchException {
if (!collection.containsKey(book.getId())) {
throw new BookNotFoundException("Not found book with id: " + book.getId());
}
var latestBook = collection.get(book.getId());
if (book.getVersion() != latestBook.getVersion()) {
throw new VersionMismatchException(
"Tried to update stale version " + book.getVersion()
+ " while actual version is " + latestBook.getVersion()
);
}
// update version, including client representation - modify by reference here
book.setVersion(book.getVersion() + 1);
// save book copy to repository
collection.put(book.getId(), new Book(book));
}
public Book get(long bookId) throws BookNotFoundException {
if (!collection.containsKey(bookId)) {
throw new BookNotFoundException("Not found book with id: " + bookId);
}
// return copy of the book
return new Book(collection.get(bookId));
}
}
以下是版本号模式的实际应用
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
}
}
}
程序输出
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
何时在 Java 中使用版本号模式
- 当你需要在分布式系统中处理并发数据修改时使用。
- 适用于数据一致性和完整性至关重要的系统。
- 非常适合使用支持版本控制或行版本控制功能的数据库的应用程序。
版本号模式 Java 教程
Java 中版本号模式的实际应用
- Hibernate (Java 持久性 API) 使用版本号来实现乐观锁。
- Microsoft SQL Server 和 Oracle 数据库支持基于版本的并发控制。
- Apache CouchDB 和其他 NoSQL 数据库为冲突解决实现了版本控制。
- Elasticsearch
- Apache Solr
版本号模式的优缺点
优点
- 提高数据一致性和完整性。
- 减少并发环境中丢失更新的可能性。
- 提供了一种检测和解决冲突的机制。
缺点
- 需要额外的逻辑来检查版本和处理冲突。
- 会导致数据库模式和应用程序逻辑的复杂性增加。
- 由于版本检查和冲突解决,可能会导致性能开销。
相关的 Java 设计模式
- 乐观离线锁:使用版本号来检测冲突,而不是防止冲突发生。
- 悲观离线锁:一种并发控制的替代方法,其中数据被锁定以进行更新,以防止冲突。