多态性是面向对象编程中的一个基本概念,允许将不同类型的对象视为同一超类的实例。这种灵活性对于创建易于扩展和维护的系统至关重要。虽然传统的SQL数据库结合Jakarta Persistence(JPA)可以处理多态数据,但NoSQL数据库具有明显优势。不同于需要严格模式定义的SQL数据库,NoSQL数据库采用无模式的方法,天然支持动态和灵活的数据结构。当与Jakarta NoSQL集成时,这种灵活性特别吸引人。Jakarta NoSQL是一个工具,它通过自定义转换器为定义和管理多态字段提供稳健的支持。
在许多企业应用程序中,存在管理不同类型数据对象的常见需求。例如,电子商务平台可能需要处理各种支付方式,如信用卡、数字钱包和银行转账,每种支付方式都有特定的属性。类似地,大型公司的资产管理系统处理不同类型的资产,如房地产、机械和知识产权,每种资产都有独特的属性。医疗保健系统必须容纳各种数据类型,从个人信息到医疗记录和测试结果。利用NoSQL数据库的多态字段可以存储和管理这些多样化的数据类型。NoSQL数据库的无模式性质使其比关系数据库更容易适应不断变化的需求。
这个教程将展示如何使用Jakarta NoSQL来管理多态字段,并使用自定义转换器。我们将包括集成使用Helidon和Oracle NoSQL的REST服务的示例代码。这个示例将演示在无模式NoSQL数据库环境中有效管理各种数据类型的多态性的实际应用。
使用NoSQL和Jakarta NoSQL的多态性
这个教程将探讨在Java世界中使用Oracle NoSQL、Java Helidon和Rest API的NoSQL和无模式功能。我们将创建一个Machine
实体,它将提供一个我们将转换为JSON的engine
字段。多亏了Oracle NoSQL的自然灵活性和无模式设计,这种方法可以无缝地工作。
第一步是创建Helidon项目,您可以使用Helidon Starter: Helidon Starter。
创建一个符合Microprofile的项目后,下一步是包含Oracle NoSQL驱动程序: Oracle NoSQL Driver。
在属性文件中,由于我们将在本地运行,我们需要两个属性:一个用于定义主机连接,第二个用于定义数据库名称:
jnosql.document.database=machines
jnosql.oracle.nosql.host=http://localhost:8080
同时,将端口更改为使用8181:
server.port=8181
下一步是配置和运行 Oracle NoSQL。为了简化操作,我们将使用 Docker,但需要注意的是,Oracle NoSQL 也支持在 Oracle 基础设施上进行云部署:
docker run -d --name oracle-instance -p 8080:8080 ghcr.io/oracle/nosql:latest-ce
通过使用 Docker,我们简化了设置过程,并确保 Oracle NoSQL 实例在受控环境中运行。这种设置为开发和测试目的提供了一种实用的方法,突出了在不同环境(包括云基础设施)部署 Oracle NoSQL 的灵活性.
设置配置和数据库后,下一步是定义 Entity
并创建 Converter
实现。在这个示例中,我们将演示 Jakarta NoSQL 和 Jakarta JSON-B 的无缝集成,展示不同的 Jakarta 规范如何有效地协作.
第一步是定义 Machine
实体,它包含一个多态 Engine
字段.
@Entity
@JsonbVisibility(FieldAccessStrategy.class)
public class Machine {
@Id
private String id;
@Column
@Convert(EngineConverter.class)
private Engine engine;
@Column
private String manufacturer;
@Column
private int year;
// 获取器和设置器
}
接下来,我们定义 Engine
类,使用 JsonbTypeInfo
指定类型和实现来处理多态性:
@JsonbTypeInfo(
key = "type",
value = {
@JsonbSubtype(alias = "gas", type = GasEngine.class),
@JsonbSubtype(alias = "electric", type = ElectricEngine.class)
}
)
@JsonbVisibility(FieldAccessStrategy.class)
public abstract class Engine {
// 通用引擎属性
// 获取器和设置器
}
引擎转换器可能因提供者而异;它可以作为 String
、Map<String, Object>
、BSON
等工作.
在设置配置和数据库后,下一步是创建应用程序和数据库桥梁。Eclipse JNoSQL集成了两个规范,Jakarta NoSQL和Jakarta Data,使用单一接口来实现这一目标。注解处理必要的步骤。
首先,我们定义MachineRepository
接口:
@Repository
public interface MachineRepository extends BasicRepository<Machine, String> {
@Query("from Machine where engine.type = :type")
List<Machine> findByType(@Param("type") String type);
}
该存储库接口允许我们直接在JSON数据中搜索元素,而不会出现任何问题,并且您可以进一步扩展它,而不会创建一个刚性的结构。
接下来,我们定义控制器来公开这个资源:
@Path("/machines")
@ApplicationScoped
public class MachineResource {
private static final Logger LOGGER = Logger.getLogger(MachineResource.class.getName());
public static final Order<Machine> ORDER_MANUFACTURER = Order.by(Sort.asc("manufacturer"));
private final MachineRepository repository;
@Inject
public MachineResource(@Database(DatabaseType.DOCUMENT) MachineRepository repository) {
this.repository = repository;
}
@GET
public List<Machine> getMachines(@QueryParam("page") @DefaultValue("1") int page, @QueryParam("page_size") @DefaultValue("10") int pageSize) {
LOGGER.info("Get machines from page " + page + " with page size " + pageSize);
Page<Machine> machines = this.repository.findAll(PageRequest.ofPage(page).size(pageSize), ORDER_MANUFACTURER);
return machines.content();
}
@GET
@Path("gas")
public List<Machine> getGasMachines() {
return this.repository.findByType("gas");
}
@GET
@Path("electric")
public List<Machine> getElectricMachines() {
return this.repository.findByType("electric");
}
@GET
@Path("{id}")
public Machine get(@PathParam("id") String id) {
LOGGER.info("Get machine by id " + id);
return this.repository.findById(id)
.orElseThrow(() -> new WebApplicationException("Machine not found with id: " + id, Response.Status.NOT_FOUND));
}
@PUT
public void save(Machine machine) {
LOGGER.info("Saving a machine " + machine);
this.repository.save(machine);
}
}
该控制器公开了管理机器的端点,包括按类型和分页获取机器。
最后,执行应用程序并使用以下curl
命令插入数据:
curl --location --request PUT 'http://localhost:8181/machines' \
--header 'Content-Type: application/json' \
--data '{
"id": "1",
"model": "Thunderbolt V8",
"engine": {
"type": "gas",
"horsepower": 450
},
"manufacturer": "Mustang",
"year": 2021,
"weight": 1600.0
}'
curl --location --request PUT 'http://localhost:8181/machines' \
--header 'Content-Type: application/json' \
--data '{
"id": "2",
"model": "Eagle Eye EV",
"engine": {
"type": "electric",
"horsepower": 300
},
"manufacturer": "Tesla",
"year": 2022,
"weight": 1400.0
}'
curl --location --request PUT 'http://localhost:8181/machines' \
--header 'Content-Type: application/json' \
--data '{
"id": "3",
"model": "Road Runner GT",
"engine": {
"type": "gas",
"horsepower": 400
},
"manufacturer": "Chevrolet",
"year": 2020,
"weight": 1700.0
}'
curl --location --request PUT 'http://localhost:8181/machines' \
--header 'Content-Type: application/json' \
--data '{
"id": "4",
"model": "Solaris X",
"engine": {
"type": "electric",
"horsepower": 350
},
"manufacturer": "Nissan",
"year": 2023,
"weight": 1350.0
}'
curl --location --request PUT 'http://localhost:8181/machines' \
--header 'Content-Type: application/json' \
--data '{
"id": "5",
"model": "Fusion Hybrid 2024",
"engine": {
"type": "electric",
"horsepower": 320
},
"manufacturer": "Toyota",
"year": 2024,
"weight": 1450.0
}'
这种设置允许您在JSON中按类型搜索,并且实现分页很容易。有关分页技术的更多信息,请参考本文。
插入一些数据后,您可以探索并了解搜索的工作原理。
- 获取带有分页的机器
- 获取所有机器
- 获取气体机器
最后的想法
使用Jakarta NoSQL和Jakarta JSON-B将多态性与NoSQL数据库集成,提供了灵活性和效率来管理不同类型的数据。通过利用NoSQL的无模式特性,这种方法简化了开发并增强了应用程序的适应性。有关完整的示例和源代码,请访问soujava/helidon-oracle-json-types。
Source:
https://dzone.com/articles/intro-to-polymorphism-with-db-engines-in-nosql