【问题标题】:Java keeping pojo datastore independentJava 保持 pojo 数据存储独立
【发布时间】:2020-04-15 03:23:56
【问题描述】:

我有一个目前使用 cassandra 进行持久化的微服务。

@Table(name = "persons")
public class Person {

 @PartitionKey
 @JsonProperty("personId")
 private UUID personId;

 @JsonProperty("personName")
 private String personName;
}

我想开始使用 mongodb 进行持久化 为此,该类需要如下所示

public class Person implements Serializable {

 @JsonSerialize(using = ObjectIdSerializer.class)
 private ObjectId personId;

 @JsonProperty("personName")
 private String personName;
}

我想知道是否有办法保持 pojo 数据存储独立,因此我应该如何创建一个通用且可以轻松与两个数据存储一起使用的 pojo?

【问题讨论】:

标签: java database mongodb cassandra microservices


【解决方案1】:

一种方法是使用单个业务域和一个存储库域。存储时,执行从通用业务域到存储库域的转换。应用程序中的所有内容都使用了业务域,因此交换数据存储应该相当简单。

此外,可以使用伪 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,因此您只需要一个服务实现)需要了解目标类型(例如 MongoPersonCassandraPerson)。您需要某种实用程序类来处理转换。也许是这样的:

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&lt;?&gt; getRepositoryDomain(),它将返回所需的存储库类,无论是Mongo、Jpa 还是Cassandra。然后,就可以获取相关的mapper并进行转换:

Mappable persistenceDomain = personRepository.getRepositoryDomain().newInstance();
return persistenceDomain.toMe().map(person, persistenceDomain);

我故意省略了更详细的细节,因为它是相当多的样板代码,但这应该可以让你理解这个想法。本质上,您不会将单个类用于多个数据库,因为这可能会很快变得混乱。考虑您将来可能还想添加 SQL 数据库支持。我看不出这些注释很好地结合在一起。

当然,根据您的实现,这也可能是矫枉过正,但它是一个可扩展的通用解决方案。

然而,重点是你有一个Person 类,它是一个 POJO。所有操作都在这个类上执行。然后将其转换为特定于数据库提供程序的实体类,这就是实际持久化的内容。这些实体类和 daos 或存储库了解业务域 (Person),但业务域不了解存储库域。

【讨论】:

  • 我们最终采用了相同的方法:业务逻辑中使用了单一持久化外观,它仅依赖于领域模型。此外,还有多个 Maven 模块提供特定于存储的实现。完全暴露 facade 的原因是某些数据库可能不支持域模型到持久性实体的直接 1:1 映射。这也是 ModelMapper 可能成为瓶颈的原因。不将内部实体限制为单一的通用结构要灵活得多。
  • 有什么具体的例子吗?我能想到我们将不可避免地遇到的一个是 NoSQL/SQL,因为数据存储的方式本质上是不同的,但我们将能够解决它。我也想不出任何 1-1 映射不起作用的地方。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-20
  • 2023-02-07
  • 2013-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多