是否可以在 Spring Boot 中将 MongoDb 和 PostgreSql 用于同一模型?

Posted

技术标签:

【中文标题】是否可以在 Spring Boot 中将 MongoDb 和 PostgreSql 用于同一模型?【英文标题】:Is it possible to use MongoDb and PostgreSql for same model in Spring boot? 【发布时间】:2021-01-15 21:05:12 【问题描述】:

我已经建立了一个用户管理服务,我在其中使用 MongoDb(弹簧数据)。我有两个模型用户和角色。

package com.userservice.usermanagement.models;

import java.util.HashSet;
import java.util.Set;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "user_data")

public class User 
    /**
     * User model
     */
    
      @Id
      private String id;

      
      private String username;

     
      private String email;

      
      private String password;
      
      private String customername;
      
      private String customerid;
      
      private String description;
      

      public String getCustomerid() 
        return customerid;
    

    public void setCustomerid(String customerid) 
        this.customerid = customerid;
    

    public String getDescription() 
        return description;
    

    public void setDescription(String description) 
        this.description = description;
    

    public String getCustomername() 
        return customername;
    

    public void setCustomername(String customername) 
        this.customername = customername;
    

    @DBRef
      private Set<Role> roles = new HashSet<>();

      public User() 
      

      public User(String username, String email, String customername,String customerid,String description, String password) 
        this.username = username;
        this.email = email;
        this.customername = customername;
        this.customerid = customerid;
        this.description = description;
        this.password = password;
      

      public String getId() 
        return id;
      

      public void setId(String id) 
        this.id = id;
      

      public String getUsername() 
        return username;
      

      public void setUsername(String username) 
        this.username = username;
      

      public String getEmail() 
        return email;
      

      public void setEmail(String email) 
        this.email = email;
      

      public String getPassword() 
        return password;
      

      public void setPassword(String password) 
        this.password = password;
      

      public Set<Role> getRoles() 
        return roles;
      

      public void setRoles(Set<Role> roles) 
        this.roles = roles;
      
    

榜样-

package com.userservice.usermanagement.models;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "roles")
public class Role 
    /**
     * Model for role with all the attributes
     */
      @Id
      private String id;

      private URole name;

      public Role() 

      

      public Role(URole name) 
        this.name = name;
      

      public String getId() 
        return id;
      

      public void setId(String id) 
        this.id = id;
      

      public URole getName() 
        return name;
      

      public void setName(URole name) 
        this.name = name;
      
    

和角色枚举器-

package com.userservice.usermanagement.models;

public enum URole 
    ROLE_USER,  
    ROLE_ADMIN

在用户中有一个角色属性,我有 @Dbref 到角色集合。我的问题是我想在这些模型的同一应用程序中选择使用 PostgreSql 和 MongoDb。我已经为 MongoDb 实现了这个,但我不确定如何在同一个应用程序中为 postgreSql 做这个作为一个选项。我认为的一种方法是拥有一个用户和角色接口,并为 User_mongo 模型和 User_postgre 实体构建两个不同的类(角色的方式相同)。我被困在这里,我尝试进行某些研究,但大多数时候我发现教程具有相同类型的单独数据库(两个 PostgreSql 数据库)。任何方向都受到高度赞赏。 PS 我是 Spring Boot 和 Java 的新手。

我现在使用 Mongorepository 的 AddUser 控制器

@PostMapping("/adduser")
//  @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> registerUser(@Valid @RequestBody SignupRequest signUpRequest) 
        /*
         * This controller Creates new user based on all the entities for the user
         * 
         */
        if (userRepository.existsByUsername(signUpRequest.getUsername())) 
            return ResponseEntity
                    .badRequest()
                    .body(new MessageResponse("Error: Username is already taken!"));
        

        if (userRepository.existsByEmail(signUpRequest.getEmail())) 
            return ResponseEntity
                    .badRequest()
                    .body(new MessageResponse("Error: Email is already in use!"));
        

        // Create new user's account
        User user = new User(signUpRequest.getUsername(), 
                             signUpRequest.getEmail(),
                             signUpRequest.getCustomername(),
                             signUpRequest.getCustomerid(),
                             signUpRequest.getDescription(),
                             encoder.encode(signUpRequest.getPassword()));
        

        Set<String> strRoles = signUpRequest.getRoles();
        Set<Role> roles = new HashSet<>();
      
        if (strRoles == null) 
            Role userRole = roleRepository.findByName(URole.ROLE_USER)
                    .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
            roles.add(userRole);
         else 
            strRoles.forEach(role -> 
                switch (role) 
                case "admin":
                    Role adminRole = roleRepository.findByName(URole.ROLE_ADMIN)
                            .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                    roles.add(adminRole);

                    break;
                
                default:
                    Role userRole = roleRepository.findByName(URole.ROLE_USER)
                            .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                    roles.add(userRole);
                
            );
        

        user.setRoles(roles);
        userRepository.save(user);

        return ResponseEntity.ok(new MessageResponse("User Added successfully!"));
    
    ```

【问题讨论】:

为什么你的模型需要 2 个数据库。我的意思是这到底是什么原因?您可以将所有与数据库相关的属性保留在 application.yaml 文件中。把不需要的注释掉。当您需要它时,取消注释并注释掉其他数据库属性。这实际上是通过配置服务器完成的。您为不同的环境(如生产、开发、QA 等)保留不同的属性集的地方......无论您需要什么环境,只需在 spring.profile 中添加值即可。 Spring boot 将从配置服务器读取值。 正确我明白了,所以这是来自不同客户的要求,其中一些需要 Mongo,而另一些需要 PostgreSql。您的方法的问题是基于这些模型我将制作存储库对吗?例如 UserService Impl 服务使用基于 mongo User 模型构建的 Userrepository 从数据库中获取数据。我不可能在那里继续评论我的代码。必须有更好的解决方案。这篇文章有些看起来相关,但不确定。 dzone.com/articles/how-springboot-autoconfiguration-magic-works 是的..这就是我告诉你的。根据您的要求使用 spring.profiles.active 指向数据库。通常在 Dev env 和 prod env 中可能有不同的数据库。出于这个原因,您使用配置文件。但是在同一个 Spring Boot 应用程序中,如果不同的模型使用不同的数据库,那么您需要配置一个类来读取不同数据库的不同数据源属性并相应地初始化您的存储库。 @Conditional 你也可以使用。 太好了,看来我的方向是正确的,但我的理解仍然存在障碍。我用我正在使用的“addUser”控制器编辑了我的问题。如您所见,我在那里有用户存储库。我的问题是当我有问题的 PostGres 数据库时,我是否必须为此创建一个存储库,在这种情况下,此代码如何更改?如果它应该是一个菜鸟问题,我很抱歉。但我专注于这部分 【参考方案1】:

我会在两个配置上使用@ConditonalOnProperty 注释(一个用于 Mongo,一个用于 PostgerSql),并在运行时添加启用的配置属性(对于您希望加载的配置)

这是一个简化的例子。

 public static void main(String[] args) 
        SpringApplication application = new SpringApplication(DemoApplication.class);
        Properties properties = new Properties();
        properties.put("databaseFoo.enabled", "true");
        application.setDefaultProperties(properties);
        application.run(args);
    
    then on the config needed when run time is databaseFoo you can annotate the bean as such
    
        @ConditionalOnProperty(
            value="databaseFoo.enabled",
            havingValue = "true")
    public class DatabaseFooConfig 
    Then the other bean could have the following conditional properties
    
            @ConditionalOnProperty(
            value="databaseBar.nabled",
            havingValue = "false",
            matchIfMissing= true)
    public class DataBaseBarConfig 

【讨论】:

是的,那么 DatabaseBarConfig 中到底发生了什么?就像在控制器的 crud 操作中我手动使用了 mongo 存储库一样,我怎样才能让它成为可选的? 在 DatabaseBarConfig 中,您可以创建所需的配置 bean。例如,一个配置 bean 提供数据源,另一个用于事务管理..等等。如果标志设置为 true,bean 将被创建为“在 springContext 中注册”。否则,它们将不会被创建,

以上是关于是否可以在 Spring Boot 中将 MongoDb 和 PostgreSql 用于同一模型?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 中将属性注入测试类?

如何在弹性beantalk中将PostgreSQL RDS连接到spring boot?

在eclipse中将Spring Boot应用程序导出为JAR文件

如何在 Spring Boot 中将 Cache-Control 标头添加到静态资源?

如何在 Spring Boot 中将大文件上传到 ftps 服务器?

在 spring-boot 项目中将 CSS 等静态文件放在哪里?