请设计一个仓库模式的实现方案,该方案需要支持数据的软删除和版本控制,以适应更加复杂的业务需求。
仓库模式实现方案:支持软删除和版本控制
1. 概述
在领域驱动设计(DDD)中,仓库模式(Repository Pattern)用于处理数据的持久化问题。为了适应更加复杂的业务需求,如支持数据的软删除和版本控制,需要对传统的仓库模式进行扩展。本文档将介绍如何设计一个支持这些功能的仓库模式。
2. 设计思路
2.1 软删除
软删除的概念指的是数据在逻辑上被删除,但在物理上仍然存在于数据库中。这可以通过在数据库表中添加一个标记字段(例如 is_deleted 或 deleted_at)来实现。当一个记录被“删除”时,实际上只是更新了这个标记字段。
2.2 版本控制
版本控制的目的是记录数据的变更历史,以便在需要时能够恢复到某个特定的版本。这可以通过在数据库表中添加版本号字段(例如 version)和时间戳字段(例如 updated_at)来实现。每当数据发生变化时,版本号递增,并记录更改的时间。
3. 数据库设计
3.1 实体表设计
假设我们有一个 Product 实体,其表结构如下:
CREATE TABLE `products` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL,
`description` TEXT,
`price` DECIMAL(10, 2) NOT NULL,
`is_deleted` BOOLEAN DEFAULT FALSE,
`deleted_at` TIMESTAMP NULL,
`version` INT DEFAULT 0,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
is_deleted:布尔值,表示该记录是否已删除(逻辑删除)。deleted_at:时间戳,记录删除的时间。version:整数,记录数据的版本号。updated_at:时间戳,记录上次更新的时间。
3.2 版本历史表设计
为了记录每个版本的变更历史,我们可以创建一个 ProductHistory 表:
CREATE TABLE `product_history` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`product_id` INT NOT NULL,
`name` VARCHAR(255) NOT NULL,
`description` TEXT,
`price` DECIMAL(10, 2) NOT NULL,
`version` INT NOT NULL,
`updated_at` TIMESTAMP NOT NULL,
FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
);
product_id:外键,关联products表的id。version:记录该版本号。updated_at:记录该版本的更新时间。
4. 仓库类设计
4.1 仓库接口
定义一个仓库接口 IProductRepository,包含基本的 CRUD 操作和扩展的功能:
public interface IProductRepository {
Product get(int id);
List<Product> getAll();
void add(Product product);
void update(Product product);
void delete(int id);
List<ProductHistory> getHistory(int id);
ProductHistory getHistoryByVersion(int id, int version);
}
4.2 仓库实现
实现上述接口,实现类 ProductRepository:
public class ProductRepository implements IProductRepository {
private final EntityManager entityManager;
public ProductRepository(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
public Product get(int id) {
return entityManager.find(Product.class, id);
}
@Override
public List<Product> getAll() {
String jpql = "SELECT p FROM Product p WHERE p.isDeleted = false";
return entityManager.createQuery(jpql, Product.class).getResultList();
}
@Override
public void add(Product product) {
entityManager.persist(product);
}
@Override
public void update(Product product) {
Product existingProduct = get(product.getId());
if (existingProduct != null) {
// 记录版本历史
ProductHistory history = new ProductHistory(existingProduct);
entityManager.persist(history);
// 更新版本号
product.setVersion(existingProduct.getVersion() + 1);
product.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
entityManager.merge(product);
}
}
@Override
public void delete(int id) {
Product product = get(id);
if (product != null) {
product.setIsDeleted(true);
product.setDeletedAt(new Timestamp(System.currentTimeMillis()));
entityManager.merge(product);
}
}
@Override
public List<ProductHistory> getHistory(int id) {
String jpql = "SELECT h FROM ProductHistory h WHERE h.productId = :id";
return entityManager.createQuery(jpql, ProductHistory.class)
.setParameter("id", id)
.getResultList();
}
@Override
public ProductHistory getHistoryByVersion(int id, int version) {
String jpql = "SELECT h FROM ProductHistory h WHERE h.productId = :id AND h.version = :version";
return entityManager.createQuery(jpql, ProductHistory.class)
.setParameter("id", id)
.setParameter("version", version)
.getSingleResult();
}
}
5. 服务层设计
服务层负责处理业务逻辑,调用仓库层的方法。这里以 ProductService 为例:
public class ProductService {
private final IProductRepository productRepository;
public ProductService(IProductRepository productRepository) {
this.productRepository = productRepository;
}
public Product getProduct(int id) {
return productRepository.get(id);
}
public List<Product> getAllProducts() {
return productRepository.getAll();
}
public void addProduct(Product product) {
productRepository.add(product);
}
public void updateProduct(Product product) {
productRepository.update(product);
}
public void deleteProduct(int id) {
productRepository.delete(id);
}
public List<ProductHistory> getProductHistory(int id) {
return productRepository.getHistory(id);
}
public ProductHistory getProductHistoryByVersion(int id, int version) {
return productRepository.getHistoryByVersion(id, version);
}
}
6. 总结
通过上述设计,我们实现了一个支持软删除和版本控制的仓库模式。这样不仅能够满足复杂业务需求,还提高了系统的可维护性和可扩展性。