一种方法是使用单个业务域和一个存储库域。存储时,执行从通用业务域到存储库域的转换。应用程序中的所有内容都使用了业务域,因此交换数据存储应该相当简单。
此外,可以使用伪 id,因此您可以在数据库提供者之间共享“主”ID。
ModelMapper 是一个可以帮助实现这一目标的库。
必不可少,像这样。一个共同的业务领域:
public class Person implements Serializable {
String id;
...
}
Mongo 实现:
public class MongoPerson implements Mappable {
@JsonSerialize(using = ObjectIdSerializer.class)
private ObjectId personId;
// pseudo ID, generated and indexed. Optional
String id;
@Override
ModelMapper fromMe() {
ModelMapper mapper = new ModelMapper();
mapper.createTypeMap(MongoPerson.class, Person.class);
return mapper;
}
@Override
ModelMapper toMe() {
ModelMapper mapper = new ModelMapper();
mapper.createTypeMap(Person.class, MongoPerson.class);
return mapper;
}
Class<?> getBusinessDomain() {
return Person.class;
}
}
如果您想保持此解决方案的通用性,这里还有一些复杂性。您的服务或 DAO(最好是 DAO,因此您只需要一个服务实现)需要了解目标类型(例如 MongoPerson、CassandraPerson)。您需要某种实用程序类来处理转换。也许是这样的:
class PersonService {
// This DAO is just an interface that targets either MongoPerson or CassandraPerson, so the implementation may be swapped out.
PersonDao<Mappable> repository;
MappableHelper helper;
Person save(Person person) {
Mappable mappable = repository.save(helper.convertToDomain(person, repository));
return helper.convertFromDomain(mappable);
}
}
在您的PersonRepository 中,您将有一个通用方法Class<?> getRepositoryDomain(),它将返回所需的存储库类,无论是Mongo、Jpa 还是Cassandra。然后,就可以获取相关的mapper并进行转换:
Mappable persistenceDomain = personRepository.getRepositoryDomain().newInstance();
return persistenceDomain.toMe().map(person, persistenceDomain);
我故意省略了更详细的细节,因为它是相当多的样板代码,但这应该可以让你理解这个想法。本质上,您不会将单个类用于多个数据库,因为这可能会很快变得混乱。考虑您将来可能还想添加 SQL 数据库支持。我看不出这些注释很好地结合在一起。
当然,根据您的实现,这也可能是矫枉过正,但它是一个可扩展的通用解决方案。
然而,重点是你有一个Person 类,它是一个 POJO。所有操作都在这个类上执行。然后将其转换为特定于数据库提供程序的实体类,这就是实际持久化的内容。这些实体类和 daos 或存储库了解业务域 (Person),但业务域不了解存储库域。