JPA:单例实体

Neb*_*chi 5 java hibernate jpa spring-data

我有一个案例要处理一个只有一个实例的实体。

情况是为Configuration类建模,该类将创建一次,更新多次,并且永不删除。

主要思想是,该实体将类似于属性文件,但保留在数据库中。

是否有对此类建模的任何建议,技巧或想法?

Art*_*kov 5

我将回答一个更普遍的问题 -如何很好地实现数据库存储的应用程序配置

一般来说,您可能有针对应用程序不同范围的配置,而不是单一的全合一配置。例如,您可能有 CarConfig、CacheConfig、BookingConfig 等,还包括一些通用的 AppConfig。有时您需要在开发过程中添加/删除属性。

因此,为了方便地处理它,我建议您使用一个将为所有配置提供服务的单个字符串键/值配置表,而不是为每个配置使用单独的表(代词将在下面描述)。方法如下:

对于每个配置,创建一个如下接口:

public interface CarConfig {       
    @PropertyName("default.color")
    @DefaultValue("red")
    String getDefaultColor();

    void setDefaultColor(String color);

    @PropertyName("max.size")
    @DefaultValue(100)
    int getMaxSize();

    void setMaxSize(int size);

    ...
}
Run Code Online (Sandbox Code Playgroud)

应用程序启动时,会实例化单个配置实现,然后在应用程序之间共享。实现是通过创建代理来完成的。

对于getter,代理分析调用的方法(例如:getDefaultColor()) - 它从注释 @PropertyName 获取属性名称。然后,它使用该属性名称查询数据库中的配置表。该值被转换(因为它作为字符串存储在表中)到方法返回类型(在 getMaxSize() 的情况下转换为 int)并返回。

对于设置器,代理将给定值保存到配置表中。无需重复 @PropertyName - 它可以从相应的 getter 派生。

因此,每当您需要配置属性值时,您都会这样:

CarConfig carConfig = configs.get(CarConfig.class);
String defaultColor = carConfig.getDefaultColor();
Run Code Online (Sandbox Code Playgroud)

为什么配置实现应该是单例并在应用程序之间共享?因为在这种情况下,您可以启用缓存 - 如果您确保配置属性始终仅通过您的配置使用,您可以在启动时读取所有值并将它们存储在内存中,然后根本不查询数据库,因为没有除了配置类之外的任何其他更改源。Setter 将更新缓存的值以及数据库配置表。

配置表看起来类似于:

|     key       |value |
...
|"default.color"|"blue"|
|"max.size"     |"85"  |
...
Run Code Online (Sandbox Code Playgroud)

因此,在单个配置表的情况下,添加新属性只需将 getter 和 setter 添加到类中即可 - 代理将自动选择它。

CUBA 开源框架中使用了类似的架构 - https://www.cuba-platform.com/

相反,为单独的配置使用单独的表具有以下优点:

  • 对于每个配置,您需要创建一个新表;
  • 添加/删除新的配置属性需要更改表架构。

  • 什么是 @PropertyName("max.size") @DefaultValue(100)?你使用什么框架? (3认同)

Gue*_*her 3

我不会将其建模为单个 JPA 实体,而是使用实现以下方法的 Facade

Configuration getConfiguration(String key);
Configuration addConfiguration(Configuration configuration);
Configuration updateConfiguration(Configuration configuration);
void deleteConfiguration(Configuration configuration);
Collection<Configuration> getCompleteConfiguration();
Run Code Online (Sandbox Code Playgroud)

当然,如果需要,您可以自由添加其他方法。该外观使用存储库来执行与持久性相关的任务。根据您的设置、复杂性和架构,您可能希望在存储库中使用的实际配置 JPA 实体与外观使用的 Configuration 类之间添加映射。

实际的 ConfigurationEntity 可能如下所示(随意添加其他 JPA 注释和/或列)

@Entity
@Table(name = "CONFIGURATION")
public class ConfigurationEntity {

    @Id
    @GeneratedValue
    private Long id;
    private String key;
    private String value;
....
Run Code Online (Sandbox Code Playgroud)